home *** CD-ROM | disk | FTP | other *** search
/ Practical Internet 2002 February / Practical Internet February 2002.iso / pc / Software / Browsing / httrack-3.09e2.exe / {app} / src / htslib.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-11-07  |  93.9 KB  |  3,606 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: Subroutines                                            */
  34. /* Author: Xavier Roche                                         */
  35. /* ------------------------------------------------------------ */
  36.  
  37. // Fichier librairie .c
  38.  
  39. #include "htslib.h"
  40. #include "htsbauth.h"
  41.  
  42. /* specific definitions */
  43. #include "htsbase.h"
  44. #include "htsnet.h"
  45. #include "htsbauth.h"
  46. #include "htsthread.h"
  47. #include "htswrap.h"
  48. #include <stdio.h>
  49. #if HTS_WIN
  50. #include <direct.h>
  51. #else
  52. #include <unistd.h>
  53. #endif
  54. #include <stdlib.h>
  55. #include <string.h>
  56. #include <time.h>
  57. #include <sys/timeb.h>
  58. #include <fcntl.h>
  59. // pour utimbuf
  60. #if HTS_WIN
  61. #include <sys/utime.h>
  62. #else
  63. #if HTS_PLATFORM!=3
  64. #include <utime.h>
  65. #else
  66. #include <utime.h>
  67. #endif
  68. #endif
  69. /* END specific definitions */
  70.  
  71.  
  72.  
  73. // DΘbuggage de contr⌠le
  74. #if HTS_DEBUG_CLOSESOCK
  75. #define _HTS_WIDE 1
  76. #endif
  77. #if HTS_WIDE_DEBUG
  78. #define _HTS_WIDE 1
  79. #endif
  80. #if _HTS_WIDE
  81. FILE* DEBUG_fp=NULL;
  82. #define DEBUG_W(A)  { if (DEBUG_fp==NULL) DEBUG_fp=fopen("bug.out","wb"); fprintf(DEBUG_fp,":>"A); fflush(DEBUG_fp); }
  83. #define DEBUG_W2(A) { if (DEBUG_fp==NULL) DEBUG_fp=fopen("bug.out","wb"); fprintf(DEBUG_fp,A); fflush(DEBUG_fp); }
  84. #endif
  85.  
  86. /* variables globales */
  87. int _DEBUG_HEAD;
  88. FILE* ioinfo;
  89.  
  90. /* dΘtection complΘmentaire */
  91. const char hts_detect[][32] = {
  92.   "archive",
  93.   "background",
  94.   "data",         // OBJECT
  95.   "dynsrc",
  96.   "lowsrc",
  97.   "profile",      // element META
  98.   "src",
  99.   "swurl",
  100.   "url",
  101.   "usemap",
  102.   ""
  103. };
  104.  
  105. /* dΘtecter dΘbut */
  106. const char hts_detectbeg[][32] = {
  107.   "hotspot",      /* hotspot1=..,hotspot2=.. */
  108.   ""
  109. };
  110.  
  111. /* ne pas dΘtcter de liens dedans */
  112. const char hts_nodetect[][32] = {
  113.   "accept-charset",
  114.   "accesskey",
  115.   "action",
  116.   "align",
  117.   "alt",
  118.   "axes",
  119.   "axis",
  120.   "char",
  121.   "charset",
  122.   "cite",
  123.   "class",
  124.   "classid",
  125.   "code",
  126.   "color",
  127.   "datetime",
  128.   "dir",
  129.   "enctype",
  130.   "face",
  131.   "height",
  132.   "id",
  133.   "lang",
  134.   "language",
  135.   "media",
  136.   "method",
  137.   "name",
  138.   "prompt",
  139.   "scheme",
  140.   "size",
  141.   "style",
  142.   "target",
  143.   "title",
  144.   "type",
  145.   "valign",
  146.   "version",
  147.   "width",
  148.   ""
  149. };
  150.  
  151.  
  152. /* dΘtection de mini-code javascript */
  153. /* ALSO USED: detection based on the name: onXXX="<tag>" where XXX starts with upper case letter */
  154. const char hts_detect_js[][32] = {
  155.   "onAbort",
  156.   "onBlur",
  157.   "onChange",
  158.   "onClick",
  159.   "onDblClick",
  160.   "onDragDrop",
  161.   "onError",
  162.   "onFocus",
  163.   "onKeyDown",
  164.   "onKeyPress",
  165.   "onKeyUp",
  166.   "onLoad",
  167.   "onMouseDown",
  168.   "onMouseMove",
  169.   "onMouseOut",
  170.   "onMouseOver",
  171.   "onMouseUp",
  172.   "onMove",
  173.   "onReset",
  174.   "onResize",
  175.   "onSelect",
  176.   "onSubmit",
  177.   "onUnload",
  178.   ""
  179. };
  180.  
  181. /* dΘtection "...URL=<url>" */
  182. const char hts_detectURL[][32] = {
  183.   "content",
  184.   ""
  185. };
  186.  
  187. /* tags o∙ l'URL doit Ωtre rΘΘcrite mais non capturΘe */
  188. const char hts_detectandleave[][32] = {
  189.   "action",
  190.   ""
  191. };
  192.  
  193. /* ne pas renommer les types renvoyΘs (couvent types inconnus) */
  194. const char hts_mime_keep[][32] = {
  195.   "application/octet-stream",
  196.   "text/plain",
  197.   ""
  198. };
  199.  
  200. /* pas de type mime connu, mais extension connue */
  201. const char hts_ext_dynamic[][32] = {
  202.   "php3",
  203.   "php",
  204.   "php4",
  205.   "php2",
  206.   "cgi",
  207.   "asp",
  208.   "jsp",
  209.   "pl",
  210.   /*"exe",*/
  211.   "cfm",
  212.   ""
  213. };
  214.  
  215. /* types MIME */
  216. const char hts_mime[][2][32] = {
  217.   {"application/acad","dwg"},
  218.   {"application/arj","arj"},
  219.   {"application/clariscad","ccad"},
  220.   {"application/drafting","drw"},
  221.   {"application/dxf","dxf"},
  222.   {"application/excel","xl"},
  223.   {"application/i-deas","unv"},
  224.   {"application/iges","isg"},
  225.   {"application/iges","iges"},
  226.   {"application/mac-binhex40","hqx"},
  227.   {"application/mac-compactpro","cpt"},
  228.   {"application/msword","doc"},
  229.   {"application/msword","w6w"},
  230.   {"application/msword","word"},
  231.   {"application/mswrite","wri"},
  232.   /*{"application/octet-stream","dms"},*/
  233.   /*{"application/octet-stream","lzh"},*/
  234.   /*{"application/octet-stream","lha"},*/
  235.   /*{"application/octet-stream","bin"},*/
  236.   {"application/oda","oda"},
  237.   {"application/pdf","pdf"},
  238.   {"application/postscript","ps"},
  239.   {"application/postscript","ai"},
  240.   {"application/postscript","eps"},
  241.   {"application/powerpoint","ppt"},
  242.   {"application/pro_eng","prt"},
  243.   {"application/pro_eng","part"},
  244.   {"application/rtf","rtf"},
  245.   {"application/set","set"},
  246.   {"application/sla","stl"},
  247.   {"application/smil","smi"},
  248.   {"application/smil","smil"},
  249.   {"application/smil","sml"},
  250.   {"application/solids","sol"},
  251.   {"application/STEP","stp"},
  252.   {"application/STEP","step"},
  253.   {"application/vda","vda"},
  254.   {"application/x-authorware-map","aam"},     
  255.   {"application/x-authorware-seg","aas"},
  256.   {"application/x-authorware-bin","aab"},
  257.   {"application/x-cocoa","cco"},
  258.   {"application/x-csh","csh"},
  259.   {"application/x-director","dir"},
  260.   {"application/x-director","dcr"},
  261.   {"application/x-director","dxr"},
  262.   {"application/x-mif","mif"},
  263.   {"application/x-dvi","dvi"},
  264.   {"application/x-gzip","gz"},
  265.   {"application/x-gzip","gzip"},
  266.   {"application/x-hdf","hdf"},
  267.   {"application/x-javascript","js"},
  268.   {"application/x-koan","skp"},
  269.   {"application/x-koan","skd"},
  270.   {"application/x-koan","skt"},
  271.   {"application/x-koan","skm"},
  272.   {"application/x-latex","latex"},
  273.   {"application/x-netcdf","nc"},
  274.   {"application/x-netcdf","cdf"},
  275.   /* {"application/x-sh","sh"}, */
  276.   /* {"application/x-csh","csh"}, */
  277.   /* {"application/x-ksh","ksh"}, */
  278.   {"application/x-shar","shar"},
  279.   {"application/x-stuffit","sit"},
  280.   {"application/x-tcl","tcl"},
  281.   {"application/x-tex","tex"},
  282.   {"application/x-texinfo","texinfo"},
  283.   {"application/x-texinfo","texi"},
  284.   {"application/x-troff","t"},
  285.   {"application/x-troff","tr"},
  286.   {"application/x-troff","roff"},
  287.   {"application/x-troff-man","man"},
  288.   {"application/x-troff-me","ms"},
  289.   {"application/x-wais-source","src"},
  290.   {"application/zip","zip"},
  291.   {"application/x-bcpio","bcpio"},
  292.   {"application/x-cdlink","vcd"},
  293.   {"application/x-cpio","cpio"},
  294.   {"application/x-gtar","tgz"},
  295.   {"application/x-gtar","gtar"},
  296.   {"application/x-shar","shar"},
  297.   {"application/x-shockwave-flash","swf"},
  298.   {"application/x-sv4cpio","sv4cpio"},
  299.   {"application/x-sv4crc","sv4crc"},
  300.   {"application/x-tar","tar"},
  301.   {"application/x-ustar","ustar"},
  302.   {"application/x-winhelp","hlp"},
  303.   {"audio/midi","mid"},
  304.   {"audio/midi","midi"},
  305.   {"audio/midi","kar"},
  306.   {"audio/mpeg","mp3"},
  307.   {"audio/mpeg","mpga"},
  308.   {"audio/mpeg","mp2"},
  309.   {"audio/basic","au"},
  310.   {"audio/basic","snd"},
  311.   {"audio/x-aiff","aif"},
  312.   {"audio/x-aiff","aiff"},
  313.   {"audio/x-aiff","aifc"},
  314.   {"audio/x-pn-realaudio","rm"},
  315.   {"audio/x-pn-realaudio","ram"},
  316.   {"audio/x-pn-realaudio","ra"},
  317.   {"audio/x-pn-realaudio-plugin","rpm"},
  318.   {"audio/x-wav","wav"},
  319.   {"chemical/x-pdb","pdb"},
  320.   {"chemical/x-pdb","xyz"},
  321.   {"drawing/x-dwf","dwf"},
  322.   {"image/gif","gif"},
  323.   {"image/ief","ief"},
  324.   {"image/jpeg","jpg"},
  325.   {"image/jpeg","jpe"},
  326.   {"image/jpeg","jpeg"},
  327.   {"image/pict","pict"},
  328.   {"image/png","png"},
  329.   {"image/tiff","tiff"},
  330.   {"image/tiff","tif"},
  331.   {"image/x-cmu-raster","ras"},
  332.   {"image/x-freehand","fh4"},
  333.   {"image/x-freehand","fh7"},
  334.   {"image/x-freehand","fh5"},  
  335.   {"image/x-freehand","fhc"},
  336.   {"image/x-freehand","fh"},   
  337.   {"image/x-portable-anymap","pnm"},
  338.   {"image/x-portable-bitmap","pgm"},
  339.   {"image/x-portable-pixmap","ppm"},
  340.   {"image/x-rgb","rgb"},
  341.   {"image/x-xbitmap","xbm"},
  342.   {"image/x-xpixmap","xpm"},
  343.   {"image/x-xwindowdump","xwd"},
  344.   {"model/mesh","msh"},  
  345.   {"model/mesh","mesh"},  
  346.   {"model/mesh","silo"},  
  347.   {"multipart/x-zip","zip"},
  348.   {"multipart/x-gzip","gzip"},
  349.   {"text/css","css"},
  350.   {"text/html","html"},
  351.   {"text/html","htm"},
  352.   {"text/plain","txt"},
  353.   {"text/plain","g"},
  354.   {"text/plain","h"},
  355.   {"text/plain","c"},
  356.   {"text/plain","cc"},
  357.   {"text/plain","hh"},
  358.   {"text/plain","m"},
  359.   {"text/plain","f90"},
  360.   {"text/richtext","rtx"},
  361.   {"text/tab-separated-values","tsv"},
  362.   {"text/x-setext","etx"},
  363.   {"text/x-sgml","sgml"},
  364.   {"text/x-sgml","sgm"},
  365.   {"text/xml","xml"},  
  366.   {"text/xml","dtd"},  
  367.   {"video/mpeg","mpeg"},
  368.   {"video/mpeg","mpg"},
  369.   {"video/mpeg","mpe"},
  370.   {"video/quicktime","qt"},
  371.   {"video/quicktime","mov"},
  372.   {"video/x-msvideo","avi"},
  373.   {"video/x-sgi-movie","movie"},
  374.   {"x-conference/x-cooltalk","ice"},
  375.   /*{"application/x-httpd-cgi","cgi"},*/
  376.   {"x-world/x-vrml","wrl"},
  377.   
  378.   {"*","class"},
  379.   
  380.   {"",""}};
  381.  
  382.  
  383. // Reserved (RFC2396)
  384. #define CHAR_RESERVED(c)  ( strchr(";/?:@&=+$,",(unsigned char)(c)) != 0 )
  385. // Delimiters (RFC2396)
  386. #define CHAR_DELIM(c)     ( strchr("<>#%\"",(unsigned char)(c)) != 0 )
  387. // Unwise (RFC2396)
  388. #define CHAR_UNWISE(c)    ( strchr("{}|\\^[]`",(unsigned char)(c)) != 0 )
  389. // Special (escape chars) (RFC2396 + >127 )
  390. #define CHAR_SPECIAL(c)   ( ((unsigned char)(c) >= 127) || ((unsigned char)(c) <= 31) )
  391. // We try to avoid them
  392. #define CHAR_XXAVOID(c)   ( strchr(" *'\"",(unsigned char)(c)) != 0 )
  393.  
  394.   
  395. // conversion Θventuelle / vers antislash
  396. #if HTS_WIN
  397. char* antislash(char* s) {
  398.   static char buff[HTS_URLMAXSIZE*2];
  399.   static char* a;
  400.   strcpy(buff,s);
  401.   while(a=strchr(buff,'/')) *a='\\';
  402.   return buff;
  403. }
  404. #endif
  405.  
  406.  
  407.  
  408. // RΘcupΘration d'un fichier http sur le net.
  409. // Renvoie une adresse sur le bloc de mΘmoire, ou bien
  410. // NULL si un retour.msgeur (buffer retour.msg) est survenue. 
  411. //
  412. // Une adresse de structure htsmsg peut Ωtre transmise pour
  413. // suivre l'Θvolution du chargement si le process a ΘtΘ lancΘ 
  414. // en background
  415.  
  416. htsblk httpget(char* url) {
  417.   char adr[HTS_URLMAXSIZE*2];   // adresse
  418.   char fil[HTS_URLMAXSIZE*2];   // chemin
  419.   
  420.   // sΘparer URL en adresse+chemin
  421.   if (ident_url_absolute(url,adr,fil)==-1) {
  422.     htsblk retour;
  423.     bzero((char *)&retour, sizeof(htsblk));    // effacer
  424.     // retour prΘdΘfini: erreur
  425.     retour.adr=NULL;
  426.     retour.size=0;
  427.     retour.msg[0]='\0';
  428.     retour.statuscode=-1;    
  429.     strcpy(retour.msg,"Error invalid URL");
  430.     return retour;
  431.   }
  432.   
  433.   return xhttpget(adr,fil);
  434. }
  435.  
  436. // ouvre une liaison http, envoie une requΦte GET et rΘceptionne le header
  437. // retour: socket
  438. int http_fopen(char* adr,char* fil,htsblk* retour) {
  439.   //                / GET, traiter en-tΩte
  440.   return http_xfopen(0,1,1,NULL,adr,fil,retour);
  441. }
  442.  
  443. // ouverture d'une liaison http, envoi d'une requΦte
  444. // mode: 0 GET  1 HEAD  [2 POST]
  445. // treat: traiter header?
  446. // waitconnect: attendre le connect()
  447. // note: dans retour, on met les params du proxy
  448. int http_xfopen(int mode,int treat,int waitconnect,char* xsend,char* adr,char* fil,htsblk* retour) {
  449.   //htsblk retour;
  450.   //int bufl=TAILLE_BUFFER;    // 8Ko de buffer
  451.   T_SOC soc=INVALID_SOCKET;
  452.   //char *p,*q;
  453.   
  454.   // retour prΘdΘfini: erreur
  455.   if (retour) {
  456.     retour->adr=NULL;
  457.     retour->size=0;
  458.     retour->msg[0]='\0';
  459.     retour->statuscode=-5;          // a priori erreur non fatale
  460.   }
  461.  
  462. #if HDEBUG
  463.   printf("adr=%s\nfichier=%s\n",adr,fil);
  464. #endif
  465.   
  466.   // ouvrir liaison
  467. #if HDEBUG
  468.   printf("CrΘation d'une socket sur %s\n",adr);
  469. #endif
  470.  
  471. #if CNXDEBUG
  472.   printf("..newhttp\n");
  473. #endif
  474.  
  475.   /* connexion */
  476.   if (retour) {
  477.     if ( (!(retour->req.proxy.active)) || (strcmp(adr,"file://")==0) ){    /* pas de proxy, ou non utilisable ici */
  478.       soc=newhttp(adr,retour,-1,waitconnect);
  479.     } else {
  480.       soc=newhttp(retour->req.proxy.name,retour,retour->req.proxy.port,waitconnect);  // ouvrir sur le proxy α la place
  481.     }
  482.   } else {
  483.     soc=newhttp(adr,NULL,-1,waitconnect);    
  484.   }
  485.  
  486.   // copier index socket retour
  487.   if (retour) retour->soc=soc;
  488.  
  489.   // --------------------
  490.   // court-circuit (court circuite aussi le proxy..)
  491.   // LOCAL_SOCKET_ID est une pseudo-socket locale
  492.   if (soc==LOCAL_SOCKET_ID) {
  493.     retour->is_file=1;  // fichier local
  494.     if (mode==0) {    // GET
  495.  
  496.       // Test en cas de file:///C|...
  497.       if (!fexist(fconv(unescape_http(fil))))
  498.         if (fexist(fconv(unescape_http(fil+1)))) {
  499.           char tempo[HTS_URLMAXSIZE*2];
  500.           strcpy(tempo,fil+1);
  501.           strcpy(fil,tempo);
  502.         }
  503.  
  504.       // Ouvrir
  505.       retour->totalsize=fsize(fconv(unescape_http(fil)));  // taille du fichier
  506.       retour->msg[0]='\0';
  507.       soc=INVALID_SOCKET;
  508.       if (retour->totalsize<0)
  509.         strcpy(retour->msg,"Unable to open file");
  510.       else if (retour->totalsize==0)
  511.         strcpy(retour->msg,"File empty");
  512.       else {
  513.         // Note: On passe par un FILE* (plus propre)
  514.         //soc=open(fil,O_RDONLY,0);    // en lecture seule!
  515.         retour->fp=fopen(fconv(unescape_http(fil)),"rb");  // ouvrir
  516.         if (retour->fp==NULL)
  517.           soc=INVALID_SOCKET;
  518.         else
  519.           soc=LOCAL_SOCKET_ID;
  520.       }
  521.       retour->soc=soc;
  522.       if (soc!=INVALID_SOCKET) {
  523.         retour->statuscode=200;   // OK
  524.         strcpy(retour->msg,"OK");
  525.         guess_httptype(retour->contenttype,fil);
  526.       } else if (strnotempty(retour->msg)==0)
  527.           strcpy(retour->msg,"Unable to open file");
  528.       return soc;  // renvoyer
  529.     } else {    // HEAD ou POST : interdit sur un local!!!! (c'est idiot!)
  530.       strcpy(retour->msg,"Unexpected Head/Post local request");
  531.       soc=INVALID_SOCKET;    // erreur
  532.       retour->soc=soc;
  533.       return soc;
  534.     }
  535.   } 
  536.   // --------------------
  537.  
  538.   if (soc!=INVALID_SOCKET) {    
  539.     char rcvd[1100];
  540.     rcvd[0]='\0';
  541. #if HDEBUG
  542.     printf("Ok, connexion rΘussie, id=%d\n",soc);
  543. #endif
  544.     
  545.     // connectΘ?
  546.     if (waitconnect) {
  547.       http_sendhead(NULL,mode,xsend,adr,fil,NULL,NULL,retour);
  548.     } 
  549.     
  550.     if (soc!=INVALID_SOCKET) {
  551.       
  552. #if HDEBUG
  553.       printf("Attente de la rΘponse:\n");
  554. #endif
  555.       
  556.       // si GET (rΘception d'un fichier), rΘceptionner en-tΩte d'abord,
  557.       // et ensuite le corps
  558.       // si POST on ne rΘceptionne rien du tout, c'est aprΦs que l'on fera
  559.       // une rΘception standard pour rΘcupΘrer l'en tΩte
  560.       if ((treat) && (waitconnect)) {  // traiter (attendre!) en-tΩte        
  561.         // RΘception de la status line et de l'en-tΩte (norme RFC1945)
  562.         
  563.         // status-line α rΘcupΘrer
  564.         finput(soc,rcvd,1024);
  565.         if (strnotempty(rcvd)==0)
  566.           finput(soc,rcvd,1024);    // "certains serveurs buggΘs envoient un \n au dΘbut" (RFC)
  567.  
  568.         // traiter status-line
  569.         treatfirstline(retour,rcvd);
  570.  
  571. #if HDEBUG
  572.         printf("Status-Code=%d\n",retour->statuscode);
  573. #endif
  574.         
  575.         // en-tΩte
  576.         
  577.         // header // ** !attention! HTTP/0.9 non supportΘ
  578.         do {
  579.           finput(soc,rcvd,1024);          
  580. #if HDEBUG
  581.           printf(">%s\n",rcvd);      
  582. #endif
  583.           if (strnotempty(rcvd))
  584.             treathead(NULL,NULL,NULL,retour,rcvd);  // traiter
  585.  
  586.         } while(strnotempty(rcvd));
  587.         
  588.         //rcvsize=-1;    // forCER CHARGEMENT INCONNU
  589.         
  590.         //if (retour)
  591.         //  retour->totalsize=rcvsize;
  592.         
  593.       } else { // si GET, on recevra l'en tΩte APRES
  594.         //rcvsize=-1;    // on ne connait pas la taille de l'en-tΩte
  595.         if (retour)
  596.           retour->totalsize=-1;
  597.       }
  598.       
  599.     }
  600.  
  601.   }
  602.     
  603.   return soc;
  604. }
  605.  
  606.  
  607. // envoi d'une requΦte
  608. int http_sendhead(t_cookie* cookie,int mode,char* xsend,char* adr,char* fil,char* referer_adr,char* referer_fil,htsblk* retour) {
  609.   char buff[8192];
  610.   //int use_11=0;     // HTTP 1.1 utilisΘ
  611.   int direct_url=0; // ne pas analyser l'url (exemple: ftp://)
  612.   char* search_tag=NULL;
  613.   buff[0]='\0';
  614.  
  615.   // header Date
  616.   //strcat(buff,"Date: ");
  617.   //time_gmt_rfc822(buff);    // obtenir l'heure au format rfc822
  618.   //sendc("\n");
  619.   //strcat(buff,buff);
  620.  
  621.   // possibilitΘ non documentΘe: >post: et >postfile:
  622.   // si prΘsence d'un tag >post: alors executer un POST
  623.   // exemple: http://www.someweb.com/test.cgi?foo>post:posteddata=10&foo=5
  624.   // si prΘsence d'un tag >postfile: alors envoyer en tΩte brut contenu dans le fichier en question
  625.   // exemple: http://www.someweb.com/test.cgi?foo>postfile:post0.txt
  626.   search_tag=strstr(fil,POSTTOK":");
  627.   if (!search_tag) {
  628.     search_tag=strstr(fil,POSTTOK"file:");
  629.     if (search_tag) {     // postfile
  630.       if (mode==0) {      // GET!
  631.         FILE* fp=fopen(unescape_http(search_tag+strlen(POSTTOK)+5),"rb");
  632.         if (fp) {
  633.           char line[1100];
  634.           char protocol[256],url[HTS_URLMAXSIZE*2],method[256];
  635.           linput(fp,line,1000);
  636.           if (sscanf(line,"%s %s %s",method,url,protocol) == 3) {
  637.             // selon que l'on a ou pas un proxy
  638.             if (retour->req.proxy.active)
  639.               sprintf(buff,"%s http://%s%s %s\r\n",method,adr,url,protocol);
  640.             else
  641.               sprintf(buff,"%s %s %s\r\n",method,url,protocol);
  642.             // lire le reste en brut
  643.             fread(buff+strlen(buff),8000-strlen(buff),1,fp);
  644.           }
  645.           fclose(fp);
  646.         }
  647.       }
  648.     }
  649.   }
  650.   // Fin postfile
  651.   
  652.   if (strnotempty(buff)==0) {    // PAS POSTFILE
  653.     // Type de requΦte?
  654.     if ((search_tag) && (mode==0)) {
  655.       strcat(buff,"POST ");
  656.     } else if (mode==0) {    // GET
  657.       strcat(buff,"GET ");
  658.     } else {  // if (mode==1) {
  659.       if (!retour->req.http11)        // forcer HTTP/1.0
  660.         strcat(buff,"GET ");      // certains serveurs (cgi) buggent avec HEAD
  661.       else
  662.         strcat(buff,"HEAD ");
  663.     }
  664.     
  665.     // si on gΦre un proxy, il faut une Absolute URI: on ajoute avant http://www.adr.dom
  666.     if (retour->req.proxy.active) {
  667.       if (!strfield(adr,"ftp://")) {
  668. #if HDEBUG
  669.         printf("Proxy Use: for %s%s proxy %d port %d\n",adr,fil,retour->req.proxy.name,retour->req.proxy.port);
  670. #endif
  671.         strcat(buff,"http://");
  672.         strcat(buff,jump_identification(adr));
  673.       } else {          // ftp:// en proxy http
  674. #if HDEBUG
  675.         printf("Proxy Use for ftp: for %s%s proxy %d port %d\n",adr,fil,retour->req.proxy.name,retour->req.proxy.port);
  676. #endif
  677.         direct_url=1;             // ne pas analyser user/pass
  678.         strcat(buff,adr);
  679.       }
  680.     } 
  681.     
  682.     // NOM DU FICHIER
  683.     // on slash doit Ωtre prΘsent en dΘbut, sinon attention aux bad request! (400)
  684.     if (*fil!='/') strcat(buff,"/");
  685.     {
  686.       char tempo[HTS_URLMAXSIZE*2];
  687.       tempo[0]='\0';
  688.       if (search_tag)
  689.         strncat(tempo,fil,(int) search_tag -(int) fil);
  690.       else
  691.         strcpy(tempo,fil);
  692.       escape_check_url(tempo);
  693.       strcat(buff,tempo);       // avec Θchappement
  694.     }
  695.     
  696.     // protocole
  697.     if (!retour->req.http11) {     // forcer HTTP/1.0
  698.       //use_11=0;
  699.       strcat(buff," HTTP/1.0\x0d\x0a");
  700.     } else {                   // RequΦte 1.1
  701.       //use_11=1;
  702.       strcat(buff," HTTP/1.1\x0d\x0a");
  703.     }
  704.  
  705.     /* supplemental data */
  706.     if (xsend) strcat(buff,xsend);    // Θventuelles autres lignes
  707.  
  708.     // tester proxy authentication
  709.     if (retour->req.proxy.active) {
  710.       char* a=jump_identification(retour->req.proxy.name);
  711.       if (a!=retour->req.proxy.name) {  // et hop, authentification proxy!
  712.         char autorisation[1100];
  713.         char user_pass[256];        
  714.         autorisation[0]=user_pass[0]='\0';
  715.         //
  716.         strncat(user_pass,retour->req.proxy.name,(int) a - (int) retour->req.proxy.name - 1);
  717.         strcpy(user_pass,unescape_http(user_pass));
  718.         code64(user_pass,autorisation);
  719.         strcat(buff,"Proxy-Authorization: Basic ");
  720.         strcat(buff,autorisation);
  721.         strcat(buff,H_CRLF);
  722. #if HDEBUG
  723.         printf("Proxy-Authenticate, %s (code: %s)\n",user_pass,autorisation);
  724. #endif
  725.       }
  726.     }
  727.     
  728.     // Referer?
  729.     if ((referer_adr) && (referer_fil)) {       // existe
  730.       if ((strnotempty(referer_adr)) && (strnotempty(referer_fil))) {   // non vide
  731.         if (strcmp(referer_adr,"file://")) {      // PAS file://
  732.           strcat(buff,"Referer: ");
  733.           strcat(buff,"http://");
  734.           strcat(buff,referer_adr);
  735.           strcat(buff,referer_fil);
  736.           strcat(buff,H_CRLF);
  737.         }
  738.       }
  739.     }
  740.     
  741.     // POST?
  742.     if (mode==0) {      // GET!
  743.       if (search_tag) {
  744.         char clen[256];
  745.         sprintf(clen,"Content-length: %d"H_CRLF,strlen(unescape_http(search_tag+strlen(POSTTOK)+1)));
  746.         strcat(buff,clen);
  747.       }
  748.     }
  749.     
  750.     // gestion cookies?
  751.     if (cookie) {
  752.       char* b=cookie->data;
  753.       int cook=0;
  754.       int max_cookies=8;
  755.       int max_size=2048;
  756.       max_size+=strlen(buff);
  757.       do {
  758.         b=cookie_find(b,"",jump_identification(adr),fil);       // prochain cookie satisfaisant aux conditions
  759.         if (b) {
  760.           max_cookies--;
  761.           if (!cook) {
  762.             strcat(buff,"Cookie: ");
  763.             strcat(buff,"$Version=1; ");
  764.             cook=1;
  765.           } else
  766.             strcat(buff,"; ");
  767.           strcat(buff,cookie_get(b,5));
  768.           strcat(buff,"=");
  769.           strcat(buff,cookie_get(b,6));
  770.           strcat(buff,"; $Path=");
  771.           strcat(buff,cookie_get(b,2));
  772.           b=cookie_nextfield(b);
  773.         }
  774.       } while( (b) && (max_cookies>0) && ((int)strlen(buff)<max_size));
  775.       if (cook) {                           // on a envoyΘ un (ou plusieurs) cookie?
  776.         strcat(buff,H_CRLF);
  777. #if DEBUG_COOK
  778.         printf("Header:\n%s\n",buff);
  779. #endif
  780.       }
  781.     }
  782.     
  783.     // connection close?
  784.     //if (use_11)     // Si on envoie une requΦte 1.1, prΘciser qu'on ne veut pas de keep-alive!!
  785.     strcat(buff,"Connection: close"H_CRLF);
  786.     
  787.     //strcat(buff,"Referer: http://");ppp
  788.     //strcat(buff,adr); 
  789.     //strcat(buff,"\n");
  790.     
  791.     // gΘrer le keep-alive (garder socket)
  792.     //strcat(buff,"Connection: Keep-Alive\n");
  793.     
  794.     {
  795.       char* real_adr=jump_identification(adr);
  796.       //if ((use_11) || (retour->user_agent_send)) {   // Pour le 1.1 on utilise un Host:
  797.       if (!direct_url) {     // pas ftp:// par exemple
  798.         //if (!retour->req.proxy.active) {
  799.         strcat(buff,"Host: "); strcat(buff,real_adr); strcat(buff,H_CRLF);
  800.         //}
  801.       }
  802.       //}
  803.  
  804.       // PrΘsence d'un user-agent?
  805.       if (retour->req.user_agent_send) {  // ohh un user-agent
  806.         char s[256];
  807.         // HyperTextSeeker/"HTSVERSION
  808.         sprintf(s,"User-Agent: %s"H_CRLF,retour->req.user_agent);
  809.         strcat(buff,s);
  810.         
  811.         // pour les serveurs difficiles
  812.         strcat(buff,"Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*"H_CRLF);
  813.         if (strnotempty(retour->req.lang_iso)) {
  814.           strcat(buff,"Accept-Language: "); strcat(buff,retour->req.lang_iso); strcat(buff,H_CRLF);
  815.         }
  816.         strcat(buff,"Accept-Charset: iso-8859-1, *"H_CRLF);   
  817.         if (retour->req.http11) {
  818. #if HTS_USEZLIB
  819.           if ((!retour->req.range_used) && (!retour->req.nocompression))
  820.             strcat(buff,"Accept-Encoding: gzip, deflate, compress, identity"H_CRLF);
  821.           else
  822.             strcat(buff,"Accept-Encoding: identity"H_CRLF);       /* no compression */
  823. #else
  824.           strcat(buff,"Accept-Encoding: identity"H_CRLF);         /* no compression */
  825. #endif
  826.         }
  827.       } else {
  828.         strcat(buff,"Accept: */*"H_CRLF);         // le minimum
  829.       }
  830.  
  831.       /* Authentification */
  832.       {
  833.         char autorisation[1100];
  834.         char* a;
  835.         autorisation[0]='\0';
  836.         if (real_adr != adr) {  // ohh une authentification!
  837.           if (!direct_url) {      // pas ftp:// par exemple
  838.             char user_pass[256];
  839.             user_pass[0]='\0';
  840.             strncat(user_pass,adr,(int) real_adr - (int) adr - 1);
  841.             strcpy(user_pass,unescape_http(user_pass));
  842.             code64(user_pass,autorisation);
  843.             if (strcmp(fil,"/robots.txt"))      /* pas robots.txt */
  844.               bauth_add(cookie,real_adr,fil,autorisation);
  845.           }
  846.         } else if ( (a=bauth_check(cookie,real_adr,fil)) )
  847.           strcpy(autorisation,a);
  848.         /* On a une autorisation a donner?  */
  849.         if (strnotempty(autorisation)) {
  850.           strcat(buff,"Authorization: Basic ");
  851.           strcat(buff,autorisation);
  852.           strcat(buff,H_CRLF);
  853.         }
  854.       }
  855.  
  856.     }
  857.     //strcat(buff,"Accept-Language: en\n");
  858.     //strcat(buff,"Accept-Charset: iso-8859-1,*,utf-8\n");
  859.     
  860.     // CRLF de fin d'en tΩte
  861.     strcat(buff,H_CRLF);
  862.     
  863.     // donnΘes complΘmentaires?
  864.     if (search_tag)
  865.     if (mode==0)      // GET!
  866.       strcat(buff,unescape_http(search_tag+strlen(POSTTOK)+1));
  867.   }
  868.   
  869. #if HDEBUG
  870. #endif
  871.   if (_DEBUG_HEAD) {
  872.     if (ioinfo) {
  873.       fprintf(ioinfo,"request for %s%s:\r\n",jump_identification(adr),fil);
  874.       fprintfio(ioinfo,buff,"<<< ");
  875.       fprintf(ioinfo,"\r\n");
  876.       fflush(ioinfo);
  877.     }
  878.   }  // Fin test pas postfile
  879.   //
  880.  
  881.   // Envoi
  882.   if (sendc(retour->soc,buff)<0) {  // ERREUR, socket rompue?...
  883.   //if (sendc(retour->soc,buff) != strlen(buff)) {  // ERREUR, socket rompue?...
  884.     deletesoc(retour->soc);  // fermer tout de mΩme
  885.     // et tenter de reconnecter
  886.     
  887.     strcpy(retour->msg,"Broken pipe");
  888.     retour->soc=INVALID_SOCKET;
  889.     /* non, α cause du poll connect()
  890.     // si on avait une connexion proxy, tenter une connexion directe cette fois!
  891.     retour->proxy.active=0;
  892.     if (retour) {
  893.     soc=newhttp(adr,retour->msg,-1,1);
  894.     retour->soc=soc;
  895.     }
  896.     else {
  897.     soc=newhttp(adr,NULL,-1,1);   
  898.     }
  899.     
  900.       // reconnectΘ?
  901.       if (soc!=INVALID_SOCKET) {        
  902.       if (sendc(soc,buff)<0) {  // NAN MARCHE PAS
  903.       strcpy(retour->msg,"Can not write to a re-established socket connexion");
  904.       deletesoc(soc);  // fermer tout de mΩme
  905.       soc=INVALID_SOCKET;
  906.       }
  907.       
  908.         } else {
  909.         strcpy(retour->msg,"Can not re-establish a socket connexion");
  910.         }
  911.     */
  912.   }
  913.   
  914.   // RX'98
  915.   return 0;
  916. }
  917.  
  918.  
  919.  
  920.  
  921. // traiter 1ere ligne d'en tΩte
  922. void treatfirstline(htsblk* retour,char* rcvd) {
  923.   char* a=rcvd;
  924.   // exemple:
  925.   // HTTP/1.0 200 OK
  926.   if (*a) {
  927.     // note: certains serveurs buggΘs renvoient HTTP/1.0\n200 OK ou " HTTP/1.0 200 OK"
  928.     while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++;      // Θpurer espaces au dΘbut
  929.     // sauter HTTP/1.x
  930.     while ((*a!=' ') && (*a!='\0') && (*a!=10) && (*a!=13) && (*a!=9)) a++;   
  931.     if (*a != '\0') {
  932.       while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++;      // Θpurer espaces
  933.       if ((*a>='0') && (*a<='9')) {
  934.         sscanf(a,"%d",&(retour->statuscode));
  935.         // sauter 200
  936.         while ((*a!=' ') && (*a!='\0') && (*a!=10) && (*a!=13) && (*a!=9)) a++;   
  937.         while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++;      // Θpurer espaces
  938.         if ((strlen(a) > 1) && (strlen(a) < 64) )                // message retour
  939.           strcpy(retour->msg,a);
  940.         else
  941.           infostatuscode(retour->msg,retour->statuscode);
  942.         // type MIME par dΘfaut
  943.         strcpy(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME);
  944.       } else {  // pas de code!
  945.         retour->statuscode=-1;
  946.         strcpy(retour->msg,"Unknown response structure");
  947.       }
  948.     } else {  // euhh??
  949.       retour->statuscode=-1;
  950.       strcpy(retour->msg,"Unknown response structure");
  951.     }
  952.   } else {  // vide!
  953.     retour->statuscode=-1;
  954.     strcpy(retour->msg,"Empty reponse or internal error");
  955.   }
  956. }
  957.  
  958. // traiter ligne par ligne l'en tΩte
  959. // gestion des cookies
  960. void treathead(t_cookie* cookie,char* adr,char* fil,htsblk* retour,char* rcvd) {
  961.   int p;
  962.   if ((p=strfield(rcvd,"Content-length:"))!=0) {
  963. #if HDEBUG
  964.     printf("ok, Content-length: dΘtectΘ\n");
  965. #endif
  966.     sscanf(rcvd+p,LLintP,&(retour->totalsize));
  967.   }
  968.   else if ((p=strfield(rcvd,"Content-Disposition:"))!=0) {
  969.     while(*(rcvd+p)==' ') p++;    // sauter espaces
  970.     if ((int) strlen(rcvd+p)<250) { // pas trop long?
  971.       char tmp[256];
  972.       char *a=NULL,*b=NULL;
  973.       strcpy(tmp,rcvd+p);
  974.       a=strstr(tmp,"filename=");
  975.       if (a) {
  976.         a+=strlen("filename=");
  977.         while(is_space(*a)) a++;
  978.         //a=strchr(a,'"');
  979.         if (a) {
  980.           char *c=NULL;
  981.           //a++;      /* jump " */
  982.           while((c=strchr(a,'/')))    /* skip all / (see RFC2616) */
  983.             a=c+1;
  984.           //b=strchr(a+1,'"');
  985.           b=a+strlen(a)-1;
  986.           while(is_space(*b)) b--;
  987.           b++;
  988.           if (b) {
  989.             *b='\0';
  990.             if ((int) strlen(a) < 200) { // pas trop long?
  991.               strcpy(retour->cdispo,a);
  992.             }
  993.           }
  994.         }
  995.       } 
  996.     }
  997.   }
  998.   else if ((p=strfield(rcvd,"Last-Modified:"))!=0) {
  999.     while(*(rcvd+p)==' ') p++;    // sauter espaces
  1000.     if ((int) strlen(rcvd+p)<64) { // pas trop long?
  1001.       //struct tm* tm_time=convert_time_rfc822(rcvd+p);
  1002.       strcpy(retour->lastmodified,rcvd+p);
  1003.     }
  1004.   }
  1005.   else if ((p=strfield(rcvd,"Date:"))!=0) {
  1006.     if (strnotempty(retour->lastmodified)==0) {          /* pas encore de last-modified */
  1007.       while(*(rcvd+p)==' ') p++;    // sauter espaces
  1008.       if ((int) strlen(rcvd+p)<64) { // pas trop long?
  1009.         //struct tm* tm_time=convert_time_rfc822(rcvd+p);
  1010.         strcpy(retour->lastmodified,rcvd+p);
  1011.       }
  1012.     }
  1013.   }
  1014.   else if ((p=strfield(rcvd,"Etag:"))!=0) {   /* Etag */
  1015.     if (retour) {
  1016.       while(*(rcvd+p)==' ') p++;    // sauter espaces
  1017.       if ((int) strlen(rcvd+p)<64)  // pas trop long?
  1018.         strcpy(retour->etag,rcvd+p);
  1019.       else    // erreur.. ignorer
  1020.         retour->etag[0]='\0';
  1021.     }
  1022.   }
  1023.   else if ((p=strfield(rcvd,"Transfer-Encoding: chunked"))!=0) {  // chunk!
  1024.     retour->is_chunk=1;     // chunked
  1025.     //retour->http11=2;     // chunked
  1026. #if HDEBUG
  1027.     printf("ok, Transfer-Encoding: dΘtectΘ\n");
  1028. #endif
  1029.   }
  1030.   else if ((p=strfield(rcvd,"Content-type:"))!=0) {
  1031.     if (retour) {
  1032.       char tempo[1100];
  1033.       // Θviter les text/html; charset=foo
  1034.       {
  1035.         char* a=strchr(rcvd+p,';');
  1036.         if (a) *a='\0';
  1037.       }
  1038.       sscanf(rcvd+p,"%s",tempo);
  1039.       if (strlen(tempo)<64)    // pas trop long!!
  1040.         strcpy(retour->contenttype,tempo);
  1041.       else
  1042.         strcpy(retour->contenttype,"application/octet-stream-unknown");    // erreur
  1043.     }
  1044.   }
  1045.   else if ((p=strfield(rcvd,"Content-Encoding:"))!=0) {
  1046.     if (retour) {
  1047.       char tempo[1100];
  1048.       {
  1049.         char* a=strchr(rcvd+p,';');
  1050.         if (a) *a='\0';
  1051.       }
  1052.       sscanf(rcvd+p,"%s",tempo);
  1053.       if (strlen(tempo)<64)    // pas trop long!!
  1054.         strcpy(retour->contentencoding,tempo);
  1055.       else
  1056.         retour->contentencoding[0]='\0';    // erreur
  1057.       if (retour->contentencoding[0])
  1058.         retour->compressed=1;
  1059.     }
  1060.   }
  1061.   else if ((p=strfield(rcvd,"Location:"))!=0) {
  1062.     if (retour) {
  1063.       if (retour->location) {
  1064.         while(*(rcvd+p)==' ') p++;    // sauter espaces
  1065.         if ((int) strlen(rcvd+p)<HTS_URLMAXSIZE)  // pas trop long?
  1066.           strcpy(retour->location,rcvd+p);
  1067.         else    // erreur.. ignorer
  1068.           retour->location[0]='\0';
  1069.       }
  1070.     }
  1071.   }
  1072.   else if ((p=strfield(rcvd,"Connection: Keep-Alive"))!=0) {
  1073.     // non, pas de keep-alive! on dΘconnectera..          
  1074.   }
  1075.   else if ((p=strfield(rcvd,"Keep-Alive:"))!=0) {    // params keep-alive
  1076.     // rien α faire          
  1077.   }
  1078.   else if ( ((p=strfield(rcvd,"Set-Cookie:"))!=0) && (cookie) ) {    // ohh un cookie
  1079.     char* a = rcvd+p;           // pointeur
  1080.     char domain[256];           // domaine cookie (.netscape.com)
  1081.     char path[256];             // chemin (/)
  1082.     char cook_name[256];        // nom cookie (MYCOOK)
  1083.     char cook_value[8192];      // valeur (ID=toto,S=1234)
  1084. #if DEBUG_COOK
  1085.     printf("set-cookie detected\n");
  1086. #endif
  1087.     while(*a) {
  1088.       char *token_st,*token_end;
  1089.       char *value_st,*value_end;
  1090.       char name[256];
  1091.       char value[8192];
  1092.       int next=0;
  1093.       name[0]=value[0]='\0';
  1094.       //
  1095.  
  1096.       // initialiser cookie lu actuellement
  1097.       if (adr)
  1098.         strcpy(domain,jump_identification(adr));     // domaine
  1099.       strcpy(path,"/");         // chemin (/)
  1100.       strcpy(cook_name,"");     // nom cookie (MYCOOK)
  1101.       strcpy(cook_value,"");    // valeur (ID=toto,S=1234)
  1102.       // boucler jusqu'au prochain cookie ou la fin
  1103.       do {
  1104.         char* start_loop=a;
  1105.         while(is_space(*a)) a++;    // sauter espaces
  1106.         token_st=a;                 // dΘpart token
  1107.         while((!is_space(*a)) && (*a) && (*a!=';') && (*a!='=')) a++;    // arrΩter si espace, point virgule
  1108.         token_end=a;
  1109.         while(is_space(*a)) a++;    // sauter espaces
  1110.         if (*a=='=') {    // name=value
  1111.           a++;
  1112.           while(is_space(*a)) a++;    // sauter espaces
  1113.           value_st=a;
  1114.           while( (*a!=';') && (*a)) a++;    // prochain ;
  1115.           //while( ((*a!='"') || (*(a-1)=='\\')) && (*a)) a++;    // prochain " (et pas \")
  1116.           value_end=a;
  1117.           //if (*a==';') {  // finit par un ;
  1118.           // vΘrifier dΘbordements
  1119.           if ( (((int) token_end - (int) token_st)<200) && (((int) value_end - (int) value_st)<8000)
  1120.             && (((int) token_end - (int) token_st)>0)   && (((int) value_end - (int) value_st)>0) ) {
  1121.             name[0]='\0';
  1122.             value[0]='\0';
  1123.             strncat(name,token_st,(int) token_end - (int) token_st);
  1124.             strncat(value,value_st,(int) value_end - (int) value_st);
  1125. #if DEBUG_COOK
  1126.             printf("detected cookie-av: name=\"%s\" value=\"%s\"\n",name,value);
  1127. #endif
  1128.             if (strfield2(name,"domain")) {
  1129.               strcpy(domain,value);
  1130.             }
  1131.             else if (strfield2(name,"path")) {
  1132.               strcpy(path,value);
  1133.             }
  1134.             else if (strfield2(name,"max-age")) {
  1135.               // ignorΘ..
  1136.             }
  1137.             else if (strfield2(name,"expires")) {
  1138.               // ignorΘ..
  1139.             }
  1140.             else if (strfield2(name,"version")) {
  1141.               // ignorΘ..
  1142.             }
  1143.             else if (strfield2(name,"comment")) {
  1144.               // ignorΘ
  1145.             }
  1146.             else if (strfield2(name,"secure")) {    // ne devrait pas arriver ici
  1147.               // ignorΘ
  1148.             }
  1149.             else {
  1150.               if (strnotempty(cook_name)==0) {          // noter premier: nom et valeur cookie
  1151.                 strcpy(cook_name,name);
  1152.                 strcpy(cook_value,value);
  1153.               } else {                             // prochain cookie
  1154.                 a=start_loop;      // on devra recommencer α cette position
  1155.                 next=1;            // enregistrer
  1156.               }
  1157.             }
  1158.           }
  1159.         }
  1160.         if (!next) {
  1161.           while((*a!=';') && (*a)) a++;    // prochain
  1162.           while(*a==';') a++;             // sauter ;
  1163.         }
  1164.       } while((*a) && (!next));
  1165.       if (strnotempty(cook_name)) {          // cookie?
  1166. #if DEBUG_COOK
  1167.         printf("new cookie: name=\"%s\" value=\"%s\" domain=\"%s\" path=\"%s\"\n",cook_name,cook_value,domain,path);
  1168. #endif
  1169.         cookie_add(cookie,cook_name,cook_value,domain,path);
  1170.       }
  1171.     }
  1172.   }
  1173. }
  1174.  
  1175.  
  1176. // transforme le message statuscode en chaεne
  1177. void infostatuscode(char* msg,int statuscode) {
  1178.   switch( statuscode) {    
  1179.     // Erreurs HTTP, selon RFC
  1180.   case 100: strcpy( msg,"Continue"); break; 
  1181.   case 101: strcpy( msg,"Switching Protocols"); break; 
  1182.   case 200: strcpy( msg,"OK"); break; 
  1183.   case 201: strcpy( msg,"Created"); break; 
  1184.   case 202: strcpy( msg,"Accepted"); break; 
  1185.   case 203: strcpy( msg,"Non-Authoritative Information"); break; 
  1186.   case 204: strcpy( msg,"No Content"); break; 
  1187.   case 205: strcpy( msg,"Reset Content"); break; 
  1188.   case 206: strcpy( msg,"Partial Content"); break; 
  1189.   case 300: strcpy( msg,"Multiple Choices"); break; 
  1190.   case 301: strcpy( msg,"Moved Permanently"); break; 
  1191.   case 302: strcpy( msg,"Moved Temporarily"); break; 
  1192.   case 303: strcpy( msg,"See Other"); break; 
  1193.   case 304: strcpy( msg,"Not Modified"); break; 
  1194.   case 305: strcpy( msg,"Use Proxy"); break; 
  1195.   case 306: strcpy( msg,"Undefined 306 error"); break; 
  1196.   case 307: strcpy( msg,"Temporary Redirect"); break; 
  1197.   case 400: strcpy( msg,"Bad Request"); break; 
  1198.   case 401: strcpy( msg,"Unauthorized"); break; 
  1199.   case 402: strcpy( msg,"Payment Required"); break; 
  1200.   case 403: strcpy( msg,"Forbidden"); break; 
  1201.   case 404: strcpy( msg,"Not Found"); break; 
  1202.   case 405: strcpy( msg,"Method Not Allowed"); break; 
  1203.   case 406: strcpy( msg,"Not Acceptable"); break; 
  1204.   case 407: strcpy( msg,"Proxy Authentication Required"); break; 
  1205.   case 408: strcpy( msg,"Request Time-out"); break; 
  1206.   case 409: strcpy( msg,"Conflict"); break; 
  1207.   case 410: strcpy( msg,"Gone"); break; 
  1208.   case 411: strcpy( msg,"Length Required"); break; 
  1209.   case 412: strcpy( msg,"Precondition Failed"); break; 
  1210.   case 413: strcpy( msg,"Request Entity Too Large"); break; 
  1211.   case 414: strcpy( msg,"Request-URI Too Large"); break; 
  1212.   case 415: strcpy( msg,"Unsupported Media Type"); break; 
  1213.   case 416: strcpy( msg,"Requested Range Not Satisfiable"); break; 
  1214.   case 417: strcpy( msg,"Expectation Failed"); break; 
  1215.   case 500: strcpy( msg,"Internal Server Error"); break; 
  1216.   case 501: strcpy( msg,"Not Implemented"); break; 
  1217.   case 502: strcpy( msg,"Bad Gateway"); break; 
  1218.   case 503: strcpy( msg,"Service Unavailable"); break; 
  1219.   case 504: strcpy( msg,"Gateway Time-out"); break; 
  1220.   case 505: strcpy( msg,"HTTP Version Not Supported"); break; 
  1221.     //
  1222.   default: if (strnotempty(msg)==0) strcpy( msg,"Unknown error"); break;
  1223.   }
  1224. }
  1225.  
  1226.  
  1227. // identique au prΘcΘdent, sauf que l'on donne adr+fil et non url complΦte
  1228. htsblk xhttpget(char* adr,char* fil) {
  1229.   T_SOC soc;
  1230.   htsblk retour;
  1231.   
  1232.   bzero((char *)&retour, sizeof(htsblk));
  1233.   soc=http_fopen(adr,fil,&retour);
  1234.  
  1235.   if (soc!=INVALID_SOCKET) {
  1236.     http_fread(soc,&retour);
  1237. #if HTS_DEBUG_CLOSESOCK
  1238.     DEBUG_W("xhttpget: deletehttp\n");
  1239. #endif
  1240.     if (retour.soc!=INVALID_SOCKET) deletehttp(&retour);  // fermer
  1241.     retour.soc=INVALID_SOCKET;
  1242.   }
  1243.   return retour;
  1244. }
  1245.  
  1246. // variation sur un thΦme...
  1247. // rΘceptionne uniquement un en-tΩte (HEAD)
  1248. // retourne dans xx.adr l'adresse pointant sur le bloc de mΘmoire de l'en tΩte
  1249. htsblk http_gethead(char* adr,char* fil) {
  1250.   T_SOC soc;
  1251.   htsblk retour;
  1252.  
  1253.   bzero((char *)&retour, sizeof(htsblk));
  1254.   soc=http_xfopen(1,0,1,NULL,adr,fil,&retour);  // HEAD, pas de traitement en-tΩte
  1255.  
  1256.   if (soc!=INVALID_SOCKET) {
  1257.     http_fread(soc,&retour);    // rΘception en-tΩte
  1258. #if HTS_DEBUG_CLOSESOCK
  1259.     DEBUG_W("http_gethead: deletehttp\n");
  1260. #endif
  1261.     if (retour.soc!=INVALID_SOCKET) deletehttp(&retour);  // fermer
  1262.     retour.soc=INVALID_SOCKET;
  1263.   }
  1264.   return retour;
  1265. }
  1266. // oui ca ressemble vachement α xhttpget - en Θtant sobre on peut voir LA diffΘrence..
  1267.  
  1268.  
  1269. // lecture sur une socket ouverte, le header a dΘja ΘtΘ envoyΘ dans le cas de GET
  1270. // il ne reste plus qu'α lire les donnΘes
  1271. // (pour HEAD le header est lu ici!)
  1272. void http_fread(T_SOC soc,htsblk* retour) {  
  1273.   //int bufl=TAILLE_BUFFER;    // 8Ko de buffer
  1274.   
  1275.   if (retour) retour->soc=soc;
  1276.   if (soc!=INVALID_SOCKET) {    
  1277.     // fonction de lecture d'une socket (plus propre)
  1278.     while(http_fread1(retour)!=-1);
  1279.     soc=retour->soc;
  1280.     if (retour->adr==NULL) {
  1281.       if (strnotempty(retour->msg)==0)
  1282.         sprintf(retour->msg,"Unable to read");
  1283.       return ;    // erreur
  1284.     } 
  1285.     
  1286. #if HDEBUG
  1287.     printf("Ok, donnΘes reτues\n");
  1288. #endif   
  1289.  
  1290.     return ;
  1291.     
  1292.   } 
  1293.   
  1294.   return ;
  1295. }
  1296.  
  1297. // check if data is available
  1298. int check_readinput(htsblk* r) {
  1299.   if (r->soc != INVALID_SOCKET) {
  1300.     fd_set fds;           // poll structures
  1301.     struct timeval tv;          // structure for select
  1302.     FD_ZERO(&fds);
  1303.     FD_SET(r->soc,&fds);           
  1304.     tv.tv_sec=0;
  1305.     tv.tv_usec=0;
  1306.     select(r->soc + 1,&fds,NULL,NULL,&tv);
  1307.     if (FD_ISSET(r->soc,&fds))
  1308.       return 1;
  1309.     else
  1310.       return 0;
  1311.   } else
  1312.     return 0;
  1313. }
  1314.  
  1315. // lecture d'un bloc sur une socket (ou un fichier!)
  1316. HTS_INLINE LLint http_fread1(htsblk* r) {
  1317.   //int bufl=TAILLE_BUFFER;  // taille d'un buffer max.
  1318.   return http_xfread1(r,TAILLE_BUFFER);
  1319. }
  1320.  
  1321. // idem, sauf qu'ici on peut choisir la taille max de donnΘes α recevoir
  1322. // SI bufl==0 alors le buffer est censΘ Ωtre de 8kos, et on recoit par bloc de lignes
  1323. // en Θliminant les cr (ex: header), arrΩt si double-lf
  1324. // SI bufl==-1 alors le buffer est censΘ Ωtre de 8kos, et on recoit ligne par ligne
  1325. // en Θliminant les cr (ex: header), arrΩt si double-lf
  1326. // Note: les +1 dans les malloc sont d√s α l'octet nul rajoutΘ en fin de fichier
  1327. LLint http_xfread1(htsblk* r,int bufl) {
  1328.   int nl=-1;
  1329.  
  1330.   if (bufl>0) {
  1331.     if (!r->is_write) {     // stocker en mΘmoire
  1332.       if (r->totalsize>0) {    // totalsize dΘterminΘ ET ALLOUE
  1333.         if (r->adr==NULL) {
  1334.           r->adr=(char*) malloct((INTsys) r->totalsize + 1);
  1335.           r->size=0;
  1336.         }
  1337.         if (r->adr!=NULL) {
  1338.           // lecture
  1339.           nl=hts_read(r,r->adr + ((int) r->size),(int) (r->totalsize-r->size) );     /* NO 32 bit overlow possible here (no 4GB html!) */
  1340.           // nouvelle taille
  1341.           if (nl>0) r->size+=nl;
  1342.           
  1343.           if ((nl<=0) || (r->size >= r->totalsize))
  1344.             nl=-1;  // break
  1345.           
  1346.           r->adr[r->size]='\0';    // caractΦre NULL en fin au cas o∙ l'on traite des HTML
  1347.         }
  1348.         
  1349.       } else {                 // inconnu..
  1350.         // rΘserver de la mΘmoire?
  1351.         if (r->adr==NULL) {
  1352. #if HDEBUG
  1353.           printf("..alloc xfread\n");
  1354. #endif
  1355.           r->adr=(char*) malloct(bufl + 1);
  1356.           r->size=0;
  1357.         }
  1358.         else {
  1359. #if HDEBUG
  1360.           printf("..realloc xfread1\n");
  1361. #endif
  1362.           r->adr=(char*) realloct(r->adr,(int)r->size+bufl + 1);
  1363.         }
  1364.         
  1365.         if (r->adr!=NULL) {
  1366.           // lecture
  1367.           nl=hts_read(r,r->adr+(int)r->size,bufl);
  1368.           if (nl>0) {
  1369.             // resize
  1370.             r->adr=(char*) realloct(r->adr,(int)r->size+nl + 1);
  1371.             // nouvelle taille
  1372.             if (nl>0) r->size+=nl;
  1373.  
  1374.             if (r->adr) r->adr[r->size]='\0';    // octet nul
  1375.  
  1376.           } // sinon on a fini
  1377. #if HDEBUG
  1378.           else
  1379.             printf("..end read (%d)\n",nl);
  1380. #endif
  1381.         }
  1382. #if HDEBUG
  1383.         else printf("..-> error\n");
  1384. #endif
  1385.       }
  1386.  
  1387.       // pas de adr=erreur
  1388.       if (r->adr==NULL) nl=-1;
  1389.  
  1390.     } else {    // stocker sur disque
  1391.       char* buff;
  1392.       buff=(char*) malloct(bufl);
  1393.       if (buff!=NULL) {
  1394.         // lecture
  1395.         nl=hts_read(r,buff,bufl);
  1396.         // nouvelle taille
  1397.         if (nl>0) { 
  1398.           r->size+=nl;
  1399.           if ((int) fwrite(buff,1,nl,r->out)!=nl) {
  1400.             r->statuscode=-1;
  1401.             strcpy(r->msg,"Write error on disk");
  1402.             nl=-1;
  1403.           }
  1404.         }
  1405.  
  1406.         if ((nl<=0) || ((r->totalsize>0) && (r->size >= r->totalsize)))
  1407.           nl=-1;  // break
  1408.  
  1409.         // libΘrer bloc tempo
  1410.         freet(buff);
  1411.       } else nl=-1;
  1412.       
  1413.       // NON ce n'est pas notre r⌠le - et cela pose des problΦmes pour la rΘception en chunk
  1414.       /*
  1415.         //if (nl<=0)    // fin
  1416.         //if (r->out!=NULL) { fclose(r->out); r->out=NULL; }
  1417.       */
  1418.       if (nl<=0)    // fin
  1419.       if (r->out!=NULL) { fflush(r->out); }
  1420.         
  1421.         
  1422.     } // stockage disque ou mΘmoire
  1423.  
  1424.   } else {    // rΘception d'un en-tΩte octet par octet
  1425.     int count=256;
  1426.     int tot_nl=0;
  1427.     int lf_detected=0;
  1428.     int at_begining=1;
  1429.     do {
  1430.       nl=-1;
  1431.       count--;
  1432.       if (r->adr==NULL) {
  1433.         r->adr=(char*) malloct(8192);
  1434.         r->size=0;
  1435.       }
  1436.       if (r->adr!=NULL) {
  1437.         if (r->size < 8190) {
  1438.           // lecture
  1439.           nl=hts_read(r,r->adr+r->size,1);
  1440.           if (nl>0) {
  1441.             // exit if:
  1442.             // lf detected AND already detected before
  1443.             // or
  1444.             // lf detected AND first character read
  1445.             if (*(r->adr+r->size) == 10) {
  1446.               if (lf_detected || (at_begining) || (bufl<0))
  1447.                 count=-1;
  1448.               lf_detected=1;
  1449.             }
  1450.             if (*(r->adr+r->size) != 13) {   // sauter caractΦres 13
  1451.               if (
  1452.                 (*(r->adr+r->size) != 10)
  1453.                 &&
  1454.                 (*(r->adr+r->size) != 13)
  1455.                 ) {
  1456.                 // restart for new line
  1457.                 lf_detected=0;
  1458.               }
  1459.               (r->size)++;
  1460.               at_begining=0;
  1461.             }
  1462.             *(r->adr+r->size)='\0';    // terminer par octet nul
  1463.           }
  1464.         }
  1465.       }
  1466.       if (nl>0) {
  1467.         tot_nl+=nl;
  1468.         if (!check_readinput(r))
  1469.           count=-1;
  1470.       }
  1471.     } while((nl>0) && (count>0));
  1472.     nl=tot_nl;
  1473.   }
  1474. #if HDEBUG
  1475.   //printf("add to %d / %d\n",r->size,r->totalsize);
  1476. #endif
  1477.   return ((nl>0)?0:-1);
  1478. }
  1479.  
  1480.  
  1481. // teste une adresse, et suit l'Θventuel chemin "moved"
  1482. // retourne 200 ou le code d'erreur (404=NOT FOUND, etc)
  1483. // copie dans loc la vΘritable adresse si celle-ci est diffΘrente
  1484. htsblk http_location(char* adr,char* fil,char* loc) {
  1485.   htsblk retour;
  1486.   int retry=0;
  1487.   int tryagain;
  1488.   // note: "RFC says"
  1489.   // 5 boucles au plus, on en teste au plus 8 ici
  1490.   // sinon abandon..
  1491.   do {
  1492.     tryagain=0;
  1493.     switch ((retour=http_test(adr,fil,loc)).statuscode) {
  1494.     case 200: break;   // ok!
  1495.     case 301: case 302: case 303: case 307: // moved!
  1496.       // recalculer adr et fil!
  1497.       if (ident_url_absolute(loc,adr,fil)!=-1) {
  1498.         tryagain=1;  // retenter
  1499.         retry++;     // ..encore une fois
  1500.       }
  1501.     }
  1502.   } while((tryagain) && (retry<5+3));
  1503.   return retour;
  1504. }
  1505.  
  1506.  
  1507. // teste si une URL (validitΘ, header, taille)
  1508. // retourne 200 ou le code d'erreur (404=NOT FOUND, etc)
  1509. // en cas de moved xx, dans location
  1510. // abandonne dΘsormais au bout de 30 secondes (aurevoir les sites
  1511. // qui nous font poireauter 5 heures..) -> -2=timeout
  1512. htsblk http_test(char* adr,char* fil,char* loc) {
  1513.   T_SOC soc;
  1514.   htsblk retour;
  1515.   //int rcvsize=-1;
  1516.   //char* rcv=NULL;    // adresse de retour
  1517.   //int bufl=TAILLE_BUFFER;    // 8Ko de buffer
  1518.   TStamp tl;
  1519.   int timeout=30;  // timeout pour un check (arbitraire) // **
  1520.  
  1521.   // pour abandonner un site trop lent
  1522.   tl=time_local();
  1523.  
  1524.   loc[0]='\0';
  1525.   bzero((char *)&retour, sizeof(htsblk));    // effacer
  1526.   retour.location=loc;    // si non nul, contiendra l'adresse vΘritable en cas de moved xx
  1527.  
  1528.   //soc=http_fopen(adr,fil,&retour,NULL);  // ouvrir, + header
  1529.  
  1530.   // on ouvre en head, et on traite l'en tΩte
  1531.   soc=http_xfopen(1,0,1,NULL,adr,fil,&retour);  // ouvrir HEAD, + envoi header
  1532.   
  1533.   if (soc!=INVALID_SOCKET) {
  1534.     int e=0;
  1535.     // tant qu'on a des donnΘes, et qu'on ne recoit pas deux LF, et que le timeout n'arrie pas
  1536.     do {
  1537.       if (http_xfread1(&retour,0)==-1)
  1538.         e=1;
  1539.       else {
  1540.         if (retour.adr!=NULL) {
  1541.           if ((retour.adr[retour.size-1]!=10) || (retour.adr[retour.size-2]!=10))
  1542.             e=1;
  1543.         }
  1544.       }
  1545.             
  1546.       if (!e) {
  1547.         if ((time_local()-tl)>=timeout) {
  1548.           e=-1;
  1549.         }
  1550.       }
  1551.       
  1552.     } while (!e);
  1553.     
  1554.     if (e==1) {
  1555.       if (adr!=NULL) {
  1556.         int ptr=0;
  1557.         char rcvd[1100];
  1558.  
  1559.         // note: en gros recopie du traitement de back_wait()
  1560.         //
  1561.  
  1562.  
  1563.         // ----------------------------------------
  1564.         // traiter en-tΩte!
  1565.         // status-line α rΘcupΘrer
  1566.         ptr+=binput(retour.adr+ptr,rcvd,1024);
  1567.         if (strnotempty(rcvd)==0)
  1568.           ptr+=binput(retour.adr+ptr,rcvd,1024);    // "certains serveurs buggΘs envoient un \n au dΘbut" (RFC)
  1569.         
  1570.         // traiter status-line
  1571.         treatfirstline(&retour,rcvd);
  1572.         
  1573. #if HDEBUG
  1574.         printf("(Buffer) Status-Code=%d\n",retour.statuscode);
  1575. #endif
  1576.         
  1577.         // en-tΩte
  1578.         
  1579.         // header // ** !attention! HTTP/0.9 non supportΘ
  1580.         do {
  1581.           ptr+=binput(retour.adr+ptr,rcvd,1024);          
  1582. #if HDEBUG
  1583.           printf("(buffer)>%s\n",rcvd);      
  1584. #endif
  1585.           if (strnotempty(rcvd))
  1586.             treathead(NULL,NULL,NULL,&retour,rcvd);  // traiter
  1587.           
  1588.         } while(strnotempty(rcvd));
  1589.         // ----------------------------------------                    
  1590.         
  1591.         // libΘrer mΘmoire
  1592.         if (retour.adr!=NULL) { freet(retour.adr); retour.adr=NULL; }
  1593.       }
  1594.     } else {
  1595.       retour.statuscode=-2;
  1596.       strcpy(retour.msg,"Timeout While Testing");
  1597.     }
  1598.     
  1599.     
  1600. #if HTS_DEBUG_CLOSESOCK
  1601.     DEBUG_W("http_test: deletehttp\n");
  1602. #endif
  1603.     deletehttp(&retour);
  1604.     retour.soc=INVALID_SOCKET;
  1605.   }
  1606.   return retour;    
  1607. }
  1608.  
  1609. // CrΘe un lien (http) vers une adresse internet iadr
  1610. // retour: structure (adresse, taille, message si erreur (si !adr))
  1611. // peut ouvrir avec des connect() non bloquants: waitconnect=0/1
  1612. int newhttp(char* _iadr,htsblk* retour,int port,int waitconnect) {  
  1613.   T_SOC soc;                           // descipteur de la socket
  1614.   char* iadr;
  1615.   // unsigned short int port;
  1616.   
  1617.   // tester un Θventuel id:pass et virer id:pass@ si dΘtectΘ
  1618.   iadr = jump_identification(_iadr);
  1619.   
  1620.   // si iadr="#" alors c'est une fausse URL, mais un vrai fichier
  1621.   // local.
  1622.   // utile pour les tests!
  1623.   //## if (iadr[0]!=lOCAL_CHAR) {
  1624.   if (strcmp(iadr,"file://")) {           /* non fichier */
  1625.     struct sockaddr_in server;
  1626.     t_hostent* hp;    
  1627.     // effacer structure
  1628.     bzero((char *)&server, sizeof(server));
  1629.  
  1630. #if HDEBUG
  1631.     printf("gethostbyname\n");
  1632. #endif
  1633.     
  1634.     // tester un Θventuel port
  1635.     if (port==-1) {
  1636.       char *a=strchr(iadr,':');
  1637.       port=80;    // port par dΘfaut
  1638.       if (a) {
  1639.         char iadr2[HTS_URLMAXSIZE*2];
  1640.         int i=-1;
  1641.         iadr2[0]='\0';
  1642.         sscanf(a+1,"%d",&i);
  1643.         if (i!=-1) {
  1644.           port=(unsigned short int) i;
  1645.         }
  1646.         
  1647.         // adresse vΘritable (sans :xx)
  1648.         strncat(iadr2,iadr,(int) a-(int) iadr);
  1649.  
  1650.         // adresse sans le :xx
  1651.         hp = hts_gethostbyname(iadr2);
  1652.         
  1653.       } else {
  1654.  
  1655.         // adresse normale (port par dΘfaut par la suite)
  1656.         hp = hts_gethostbyname(iadr);
  1657.         
  1658.       }
  1659.       
  1660.     } else    // port dΘfini
  1661.       hp = hts_gethostbyname(iadr);
  1662.  
  1663.     
  1664.     // Conversion iadr -> adresse
  1665.     // structure recevant le nom de l'h⌠te, etc
  1666.     //struct     hostent     *hp;
  1667.     if (hp == NULL) {
  1668. #if DEBUG
  1669.       printf("erreur gethostbyname\n");
  1670. #endif
  1671.       if (retour)
  1672.       if (retour->msg)
  1673.         strcpy(retour->msg,"Unable to get server's address");
  1674.       return INVALID_SOCKET;
  1675.     }  
  1676.     // copie adresse
  1677.     bcopy(hp->h_addr, (char *)&server.sin_addr, hp->h_length);
  1678.  
  1679.     
  1680.     // crΘer ("attachement") une socket (point d'accΦs) internet,en flot
  1681. #if HDEBUG
  1682.     printf("socket\n");
  1683. #endif
  1684. #if HTS_WIDE_DEBUG    
  1685.     DEBUG_W("socket\n");
  1686. #endif
  1687.     soc=socket(AF_INET,SOCK_STREAM,0);
  1688. #if HTS_WIDE_DEBUG    
  1689.     DEBUG_W("socket done\n");
  1690. #endif
  1691.     if (soc==INVALID_SOCKET) {
  1692.       if (retour)
  1693.       if (retour->msg)
  1694.         strcpy(retour->msg,"Unable to create a socket");
  1695.       return INVALID_SOCKET;                        // erreur crΘation socket impossible
  1696.     }
  1697.     // structure: connexion au domaine internet, port 80 (ou autre)
  1698.     server.sin_family = AF_INET;
  1699.     server.sin_port = htons((unsigned short int) port);
  1700. #if HDEBUG
  1701.     printf("==%d\n",soc);
  1702. #endif
  1703.  
  1704.     // connexion non bloquante?
  1705.     if (!waitconnect ) {
  1706.       unsigned long p=1;  // non bloquant
  1707. #if HTS_WIN
  1708.       ioctlsocket(soc,FIONBIO,&p);
  1709. #else
  1710.       ioctl(soc,FIONBIO,&p);
  1711. #endif
  1712.     }
  1713.     
  1714.     // Connexion au serveur lui mΩme
  1715. #if HDEBUG
  1716.     printf("connect\n");
  1717. #endif
  1718.     
  1719. #if HTS_WIDE_DEBUG
  1720.     DEBUG_W("connect\n");
  1721. #endif
  1722. #if HTS_WIN
  1723.     if (connect(soc, (const struct sockaddr FAR *)&server, sizeof(server)) != 0) {
  1724. #else
  1725.       if (connect(soc, (struct sockaddr *)&server, sizeof(server)) == -1) {
  1726. #endif
  1727.         // bloquant
  1728.         if (waitconnect) {
  1729. #if HDEBUG
  1730.           printf("unable to connect!\n");
  1731. #endif
  1732.           if (retour)
  1733.           if (retour->msg)
  1734.             strcpy(retour->msg,"Unable to connect to the server");
  1735.           deletesoc(soc);
  1736.           return INVALID_SOCKET;
  1737.         }
  1738.       }
  1739. #if HTS_WIDE_DEBUG    
  1740.       DEBUG_W("connect done\n");
  1741. #endif
  1742.       
  1743. #if HDEBUG
  1744.       printf("connexion Θtablie\n");
  1745. #endif
  1746.     
  1747.     // A partir de maintenant, on peut envoyer et recevoir des donnΘes
  1748.     // via le flot identifiΘ par soc (socket): write(soc,adr,taille) et 
  1749.     // read(soc,adr,taille)
  1750.  
  1751.   } else {    // on doit ouvrir un fichier local!
  1752.     // il sera gΘrΘ de la mΩme maniΦre qu'une socket (c'est idem!)
  1753.  
  1754.     soc=LOCAL_SOCKET_ID;    // pseudo-socket locale..
  1755.     // soc sera remplacΘ lors d'un http_fopen() par un handle vΘritable!
  1756.  
  1757.   }   // teste fichier local ou http
  1758.   
  1759.   return soc;
  1760. }
  1761.  
  1762.  
  1763.  
  1764. // couper http://www.truc.fr/pub/index.html -> www.truc.fr /pub/index.html
  1765. // retour=-1 si erreur.
  1766. // si file://... alors adresse=file:// (et coupe le ?query dans ce cas)
  1767. int ident_url_absolute(char* url,char* adr,char* fil) {
  1768.   int pos=0;
  1769.   int scheme=0;
  1770.  
  1771.   // effacer adr et fil
  1772.   adr[0]=fil[0]='\0';
  1773.   
  1774. #if HDEBUG
  1775.   printf("protocol: %s\n",url);
  1776. #endif
  1777.  
  1778.   // Scheme?
  1779.   {
  1780.     char* a=url;
  1781.     while (isalpha((unsigned char)*a))
  1782.       a++;
  1783.     if (*a == ':')
  1784.       scheme=1;
  1785.   }
  1786.  
  1787.   // 1. optional scheme ":"
  1788.   if ((pos=strfield(url,"file:"))) {    // fichier local!! (pour les tests)
  1789.     //!! p+=3;
  1790.     strcpy(adr,"file://");
  1791.   } else if ((pos=strfield(url,"http:"))) {    // HTTP
  1792.     //!!p+=3;
  1793.   } else if ((pos=strfield(url,"ftp:"))) {    // FTP
  1794.     strcpy(adr,"ftp://");    // FTP!!
  1795.     //!!p+=3;
  1796.   } else if (scheme) {
  1797.     return -1;    // erreur non reconnu
  1798.   } else
  1799.     pos=0;
  1800.  
  1801.   // 2. optional "//" authority
  1802.   if (strfield(url+pos,"//")) {
  1803.     pos+=2;
  1804.   }
  1805.  
  1806.   // (url+pos) now points to the path (not net path)
  1807.  
  1808.   //## if (adr[0]!=lOCAL_CHAR) {    // adresse normale http
  1809.   if (!strfield(adr,"file:")) {      // PAS file://
  1810.     char *p,*q;
  1811.     p=url+pos;
  1812.  
  1813.     // p pointe sur le dΘbut de l'adresse, ex: www.truc.fr/sommaire/index.html
  1814.     q=strchr(jump_identification(p),'/');
  1815.     if (q==0) q=p+strlen(p);  // pointe sur \0
  1816.     // q pointe sur le chemin, ex: index.html?query=recherche
  1817.     
  1818.     // chemin www... trop long!!
  1819.     if ( ( ((int) q)- ((int) p) )  > HTS_URLMAXSIZE) {
  1820.       //strcpy(retour.msg,"Path too long");
  1821.       return -1;    // erreur
  1822.     }
  1823.     
  1824.     // recopier adresse www..
  1825.     strncat(adr,p, ((int) q) - ((int) p) );
  1826.     // *( adr+( ((int) q) - ((int) p) ) )=0;  // faut arrΩter la fumette!
  1827.     // recopier chemin /pub/..
  1828.     strcat(fil,q);
  1829.     if (strnotempty(fil)==0)    // page par dΘfaut (/)
  1830.       strcat(fil,"/");
  1831.     // SECURITE:
  1832.     // simplifier url pour les ../
  1833.     fil_simplifie(fil);
  1834.   } else {    // localhost file://
  1835.     char *p;
  1836.     int i;
  1837.     char* a;
  1838.  
  1839.     p=url+pos;
  1840.     
  1841.     strcat(fil,p);    // fichier local ; adr="#"
  1842.     a=strchr(fil,'?');
  1843.     if (a) 
  1844.       *a='\0';      /* couper query (inutile pour file:// lors de la requΩte) */
  1845.     // filtrer les \\ -> / pour les fichiers DOS
  1846.     for(i=0;i<(int) strlen(fil);i++)
  1847.       if (fil[i]=='\\')
  1848.         fil[i]='/';
  1849.   }
  1850.  
  1851.   // no hostname
  1852.   if (!strnotempty(adr))
  1853.     return -1;    // erreur non reconnu
  1854.  
  1855.   // nommer au besoin.. (non utilisΘ normalement)
  1856.   if (!strnotempty(fil))
  1857.     strcpy(fil,"default-index.html");
  1858.  
  1859.   // case insensitive pour adresse
  1860.   {
  1861.     char *a=jump_identification(adr);
  1862.     while(*a) {
  1863.       if ((*a>='A') && (*a<='Z'))
  1864.         *a+='a'-'A';       
  1865.       a++;
  1866.     }
  1867.   }
  1868.   
  1869.   return 0;
  1870. }
  1871.  
  1872. // simplification des ../
  1873. void fil_simplifie(char* f) {
  1874.   int i=0;
  1875.   int last=0;
  1876.   char* a;
  1877.  
  1878.   // Θliminer ../
  1879.   while (f[i]) {
  1880.     
  1881.     if (f[i]=='/') {
  1882.       if (f[i+1]=='.')
  1883.       if (f[i+2]=='.')      // couper dernier rΘpertoire
  1884.       if (f[i+3]=='/')      // Θviter les /tmp/..coolandlamedir/
  1885.       {    // couper dernier rΘpertoire
  1886.         char tempo[HTS_URLMAXSIZE*2];
  1887.         tempo[0]='\0';
  1888.         //
  1889.         if (!last)                /* can't go upper.. */
  1890.           strcpy(tempo,"/");
  1891.         else
  1892.           strncpy(tempo,f,last+1);
  1893.         tempo[last+1]='\0';
  1894.         strcat(tempo,f+i+4);
  1895.         strcpy(f,tempo);    // remplacer
  1896.         i=-1;             // recommencer
  1897.         last=0;
  1898.       }
  1899.       
  1900.       if (i>=0)
  1901.         last=i;
  1902.       else
  1903.         last=0;
  1904.     }
  1905.     
  1906.     i++;
  1907.   }
  1908.  
  1909.   // Θliminer ./
  1910.   while ( (a=strstr(f,"./")) ) {
  1911.     char tempo[HTS_URLMAXSIZE*2];
  1912.     tempo[0]='\0';
  1913.     strcpy(tempo,a+2);
  1914.     strcpy(a,tempo);
  1915.   }
  1916.   // delete all remaining ../ (potential threat)
  1917.   while ( (a=strstr(f,"../")) ) {
  1918.     char tempo[HTS_URLMAXSIZE*2];
  1919.     tempo[0]='\0';
  1920.     strcpy(tempo,a+3);
  1921.     strcpy(a,tempo);
  1922.   }
  1923.   
  1924. }
  1925.  
  1926.  
  1927. // fermer liaison fichier ou socket
  1928. HTS_INLINE void deletehttp(htsblk* r) {
  1929. #if HTS_DEBUG_CLOSESOCK
  1930.     char info[256];
  1931.     sprintf(info,"deletehttp: (htsblk*) %d\n",r);
  1932.     DEBUG_W2(info);
  1933. #endif
  1934.   if (r->soc!=INVALID_SOCKET) {
  1935.     if (r->is_file) {
  1936.       if (r->fp)
  1937.         fclose(r->fp);
  1938.       r->fp=NULL;
  1939.     } else {
  1940.       if (r->soc!=LOCAL_SOCKET_ID)
  1941.         deletesoc(r->soc);
  1942.     }
  1943.     r->soc=INVALID_SOCKET;
  1944.   }
  1945. }
  1946.  
  1947. // fermer une socket
  1948. HTS_INLINE void deletesoc(T_SOC soc) {
  1949.   if (soc!=INVALID_SOCKET) {
  1950. // J'ai plantΘ.. pas de shutdown
  1951. //#if HTS_WIDE_DEBUG    
  1952. //    DEBUG_W("shutdown\n");
  1953. //#endif
  1954. //    shutdown(soc,2);  // shutdown
  1955. //#if HTS_WIDE_DEBUG    
  1956. //    DEBUG_W("shutdown done\n");
  1957. //#endif
  1958.     // Ne pas oublier de fermer la connexion avant de partir.. (plus propre)
  1959. #if HTS_WIDE_DEBUG    
  1960.     DEBUG_W("close\n");
  1961. #endif
  1962. #if HTS_WIN
  1963.     closesocket(soc);
  1964. #else
  1965.     close(soc);
  1966. #endif
  1967. #if HTS_WIDE_DEBUG    
  1968.     DEBUG_W("close done\n");
  1969. #endif
  1970.   }
  1971. }
  1972.  
  1973. // renvoi le nombre de secondes depuis 1970
  1974. HTS_INLINE TStamp time_local(void) {
  1975.   return ((TStamp) time(NULL));
  1976. }
  1977.  
  1978. // number of millisec since 1970
  1979. HTS_INLINE TStamp mtime_local(void) {
  1980. #ifndef HTS_DO_NOT_USE_FTIME
  1981.   struct timeb B;
  1982.   ftime( &B );
  1983.   return (TStamp) ( ((TStamp) B.time * (TStamp) 1000)
  1984.         + ((TStamp) B.millitm) );
  1985. #else
  1986.   // not precise..
  1987.   return (TStamp) ( ((TStamp) time_local() * (TStamp) 1000)
  1988.         + ((TStamp) 0) );
  1989. #endif
  1990. }
  1991.  
  1992. // convertit un nombre de secondes en temps (chaine)
  1993. void sec2str(char *st,TStamp t) {
  1994.   int j,h,m,s;
  1995.   
  1996.   j=(int) (t/(3600*24));
  1997.   t-=((TStamp) j)*(3600*24);
  1998.   h=(int) (t/(3600));
  1999.   t-=((TStamp) h)*3600;
  2000.   m=(int) (t/60);
  2001.   t-=((TStamp) m)*60;
  2002.   s=(int) t;
  2003.   
  2004.   if (j>0)
  2005.     sprintf(st,"%d days, %d hours %d minutes %d seconds",j,h,m,s);
  2006.   else if (h>0)
  2007.     sprintf(st,"%d hours %d minutes %d seconds",h,m,s);
  2008.   else if (m>0)
  2009.     sprintf(st,"%d minutes %d seconds",m,s);
  2010.   else
  2011.     sprintf(st,"%d seconds",s);
  2012. }
  2013.  
  2014. // idem, plus court (chaine)
  2015. void qsec2str(char *st,TStamp t) {
  2016.   int j,h,m,s;
  2017.   
  2018.   j=(int) (t/(3600*24));
  2019.   t-=((TStamp) j)*(3600*24);
  2020.   h=(int) (t/(3600));
  2021.   t-=((TStamp) h)*3600;
  2022.   m=(int) (t/60);
  2023.   t-=((TStamp) m)*60;
  2024.   s=(int) t;
  2025.   
  2026.   if (j>0)
  2027.     sprintf(st,"%dd,%02dh,%02dmin%02ds",j,h,m,s);
  2028.   else if (h>0)
  2029.     sprintf(st,"%dh,%02dmin%02ds",h,m,s);
  2030.   else if (m>0)
  2031.     sprintf(st,"%dmin%02ds",m,s);
  2032.   else
  2033.     sprintf(st,"%ds",s);
  2034. }
  2035.  
  2036.  
  2037. // heure actuelle, GMT, format rfc (taille buffer 256o)
  2038. void time_gmt_rfc822(char* s) {
  2039.   time_t tt;
  2040.   struct tm* A;
  2041.   tt=time(NULL);
  2042.   A=gmtime(&tt);
  2043.   if (A==NULL)
  2044.     A=localtime(&tt);
  2045.   time_rfc822(s,A);
  2046. }
  2047.  
  2048. // heure actuelle, format rfc (taille buffer 256o)
  2049. void time_local_rfc822(char* s) {
  2050.   time_t tt;
  2051.   struct tm* A;
  2052.   tt=time(NULL);
  2053.   A=localtime(&tt);
  2054.   time_rfc822_local(s,A);
  2055. }
  2056.  
  2057. /* convertir une chaine en temps */
  2058. struct tm* convert_time_rfc822(char* s) {
  2059.   static struct tm result;
  2060.   /* */
  2061.   char months[]="jan feb mar apr may jun jul aug sep oct nov dec";
  2062.   char str[256];
  2063.   char* a;
  2064.   /* */
  2065.   int result_mm=-1;
  2066.   int result_dd=-1;
  2067.   int result_n1=-1;
  2068.   int result_n2=-1;
  2069.   int result_n3=-1;
  2070.   int result_n4=-1;
  2071.   /* */
  2072.   if ((int) strlen(s) > 200)
  2073.     return NULL;
  2074.   strcpy(str,s);
  2075.   hts_lowcase(str);
  2076.   /* Θliminer :,- */
  2077.   while( (a=strchr(str,'-')) ) *a=' ';
  2078.   while( (a=strchr(str,':')) ) *a=' ';
  2079.   while( (a=strchr(str,',')) ) *a=' ';
  2080.   /* tokeniser */
  2081.   a=str;
  2082.   while(*a) {
  2083.     char *first,*last;
  2084.     char tok[256];
  2085.     /* dΘcouper mot */
  2086.     while(*a==' ') a++;   /* sauter espaces */
  2087.     first=a;
  2088.     while((*a) && (*a!=' ')) a++;
  2089.     last=a;
  2090.     tok[0]='\0';
  2091.     if (first!=last) {
  2092.       char* pos;
  2093.       strncat(tok,first,(int) last-(int) first);
  2094.       /* analyser */
  2095.       if ( (pos=strstr(months,tok)) ) {               /* month always in letters */
  2096.         result_mm=((int) pos-(int) months)/4;
  2097.       } else {
  2098.         int number;
  2099.         if (sscanf(tok,"%d",&number) == 1) {      /* number token */
  2100.           if (result_dd<0)                        /* day always first number */
  2101.             result_dd=number;
  2102.           else if (result_n1<0)
  2103.             result_n1=number;
  2104.           else if (result_n2<0)
  2105.             result_n2=number;
  2106.           else if (result_n3<0)
  2107.             result_n3=number;
  2108.           else if (result_n4<0)
  2109.             result_n4=number;
  2110.         }   /* sinon, bruit de fond(+1GMT for exampel) */
  2111.       }
  2112.     }
  2113.   }
  2114.   if ((result_n1>=0) && (result_mm>=0) && (result_dd>=0) && (result_n2>=0) && (result_n3>=0) && (result_n4>=0)) {
  2115.     if (result_n4>=1000) {               /* Sun Nov  6 08:49:37 1994 */
  2116.       result.tm_year=result_n4-1900;
  2117.       result.tm_hour=result_n1;
  2118.       result.tm_min=result_n2;
  2119.       result.tm_sec=max(result_n3,0);
  2120.     } else {                            /* Sun, 06 Nov 1994 08:49:37 GMT or Sunday, 06-Nov-94 08:49:37 GMT */
  2121.       result.tm_hour=result_n2;
  2122.       result.tm_min=result_n3;
  2123.       result.tm_sec=max(result_n4,0);
  2124.       if (result_n1<=50)                /* 00 means 2000 */
  2125.         result.tm_year=result_n1+100;
  2126.       else if (result_n1<1000)          /* 99 means 1999 */
  2127.         result.tm_year=result_n1;
  2128.       else                              /* 2000 */
  2129.         result.tm_year=result_n1-1900;
  2130.     }
  2131.     result.tm_isdst=0;        /* assume GMT */
  2132.     result.tm_yday=-1;        /* don't know */
  2133.     result.tm_wday=-1;        /* don't know */
  2134.     result.tm_mon=result_mm;
  2135.     result.tm_mday=result_dd;
  2136.     return &result;
  2137.   }
  2138.   return NULL;
  2139. }
  2140.  
  2141. /* sets file time. -1 if error */
  2142. int set_filetime(char* file,struct tm* tm_time) {
  2143.   struct utimbuf tim;
  2144. #ifndef HTS_DO_NOT_USE_FTIME
  2145.   struct timeb B;
  2146.   B.timezone=0;
  2147.   ftime( &B );
  2148.   tim.actime=tim.modtime=mktime(tm_time) - B.timezone*60; 
  2149. #else
  2150.   // bogus time (GMT/local)..
  2151.   tim.actime=tim.modtime=mktime(tm_time); 
  2152. #endif
  2153.   return utime(file,&tim);
  2154. }
  2155.  
  2156. /* sets file time from RFC822 date+time, -1 if error*/
  2157. int set_filetime_rfc822(char* file,char* date) {
  2158.   struct tm* tm_s=convert_time_rfc822(date);
  2159.   if (tm_s) {
  2160.     return set_filetime(file,tm_s);
  2161.   } else return -1;
  2162. }
  2163.  
  2164.  
  2165. // heure au format rfc (taille buffer 256o)
  2166. HTS_INLINE void time_rfc822(char* s,struct tm * A) {
  2167.   strftime(s,256,"%a, %d %b %Y %H:%M:%S GMT",A);
  2168. }
  2169.  
  2170. // heure locale au format rfc (taille buffer 256o)
  2171. HTS_INLINE void time_rfc822_local(char* s,struct tm * A) {
  2172.   strftime(s,256,"%a, %d %b %Y %H:%M:%S",A);
  2173. }
  2174.  
  2175. // conversion en b,Kb,Mb
  2176. char* int2bytes(LLint n) {
  2177.   static char buff[256];
  2178.   char** a=int2bytes2(n);
  2179.   strcpy(buff,a[0]);
  2180.   strcat(buff,a[1]);
  2181.   return concat(buff,"");
  2182. }
  2183.  
  2184. // conversion en b/s,Kb/s,Mb/s
  2185. char* int2bytessec(long int n) {
  2186.   static char buff[256];
  2187.   char** a=int2bytes2(n);
  2188.   strcpy(buff,a[0]);
  2189.   strcat(buff,a[1]);
  2190.   return concat(buff,"/s");
  2191. }
  2192. char* int2char(int n) {
  2193.   static char buffer[32];
  2194.   sprintf(buffer,"%d",n);
  2195.   return concat(buffer,"");
  2196. }
  2197.  
  2198. // conversion en b,Kb,Mb, nombre et type sΘparΘs
  2199. // limite: 2.10^9.10^6B
  2200. char** int2bytes2(LLint n) {
  2201.   static char buff1[256];
  2202.   static char buff2[32];
  2203.   static char* buffadr[2];
  2204.   if (n<1024) {
  2205.     sprintf(buff1,"%d",(int)(LLint)n);
  2206.     strcpy(buff2,"B");
  2207.   } else if (n < (LLint)(1024*1024)) {
  2208.     sprintf(buff1,"%d,%02d",(int)(LLint)(n/1024),(int)(LLint)((n%1024)*100)/1024);
  2209.     strcpy(buff2,"KB");
  2210.   }
  2211. #ifdef HTS_LONGLONG
  2212.   else if (n < (LLint)(1024*1024*1024)) {
  2213.     sprintf(buff1,"%d,%02d",(int)(LLint)(n/(1024*1024)),(int)(LLint)(((n%(1024*1024))*100)/(1024*1024)));
  2214.     strcpy(buff2,"MB");
  2215.   } else {
  2216.     sprintf(buff1,"%d,%02d",(int)(LLint)(n/(1024*1024*1024)),(int)(LLint)(((n%(1024*1024*1024))*100)/(1024*1024*1024)));
  2217.     strcpy(buff2,"GB");
  2218.   }
  2219. #else
  2220.   else {
  2221.     sprintf(buff1,"%d,%02d",(int)(LLint)(n/(1024*1024)),(int)(LLint)(((n%(1024*1024))*100)/(1024*1024)));
  2222.     strcpy(buff2,"MB");
  2223.   }
  2224. #endif
  2225.   buffadr[0]=buff1;
  2226.   buffadr[1]=buff2;
  2227.   return buffadr;
  2228. }
  2229.  
  2230.  
  2231. // envoi de texte (en tΩtes gΘnΘralement) sur la socket soc
  2232. HTS_INLINE int sendc(T_SOC soc,char* s) {
  2233. #if HDEBUG
  2234.   write(0,s,strlen(s));
  2235. #endif
  2236. //#if HTS_WIN
  2237.   return send(soc,s,strlen(s),0);
  2238. //#else
  2239. //  return write(soc,s,strlen(s));
  2240. //#endif
  2241. }
  2242.  
  2243.  
  2244. // Remplace read
  2245. void finput(int fd,char* s,int max) {
  2246.   static char c;
  2247.   register int j=0;
  2248.   do {
  2249.     //c=fgetc(fp);
  2250.     if (read(fd,&c,1)<=0) {
  2251.       c=0;
  2252.     }
  2253.     if (c!=0) {
  2254.       switch(c) {
  2255.       case 10: c=0; break;
  2256.       case 13: break;  // sauter ces caractΦres
  2257.       default: s[j++]=c; break;
  2258.       }
  2259.     }
  2260.   }  while((c!=0) && (j<max-1));
  2261.   s[j++]='\0';
  2262.  
  2263. // Like linput, but in memory (optimized)
  2264. int binput(char* buff,char* s,int max) {
  2265.   char* end;
  2266.   int count;
  2267.  
  2268.   // clear buffer
  2269.   s[0]='\0';
  2270.   // end of buffer?
  2271.   if ( *buff == '\0')
  2272.     return 0;
  2273.   // find ending \n
  2274.   end=strchr(buff,'\n');
  2275.   // ..or end of buffer
  2276.   if (!end)
  2277.     end=buff+strlen(buff);
  2278.   // then count number of bytes, maximum=max
  2279.   count=min(max,end-buff);
  2280.   // and strip annoying ending cr
  2281.   while( (count>0) && (buff[count] == '\r'))
  2282.     count--;
  2283.   // copy
  2284.   bcopy(buff,s,count);        // strncat(s,buff,count);
  2285.   // and terminate with a null char
  2286.   s[count]='\0';
  2287.   // then return the supplemental jump offset
  2288.   return (end-buff)+1;
  2289.  
  2290. // Remplace fscanf(fp,"%s",s)
  2291. void linput(FILE* fp,char* s,int max) {
  2292.   register int c;
  2293.   register int j=0;
  2294.   do {
  2295.     c=fgetc(fp);
  2296.     if (c!=EOF) {
  2297.       switch(c) {
  2298.         case 13: break;  // sauter CR
  2299.         case 10: c=-1; break;
  2300.         case 9: case 12: break;  // sauter ces caractΦres
  2301.         default: s[j++]=(char) c; break;
  2302.       }
  2303.     }
  2304.   }  while((c!=-1) && (c!=EOF) && (j<(max-1)));
  2305.   s[j++]='\0';
  2306. }
  2307. void linput_trim(FILE* fp,char* s,int max) {
  2308.   char* ls=(char*) malloct(max+2);
  2309.   if (ls) {
  2310.     char* a;
  2311.     // lire ligne
  2312.     linput(fp,ls,max);
  2313.     // sauter espaces et tabs en fin
  2314.     while((ls[strlen(ls)-1]==' ') || (ls[strlen(ls)-1]=='\t')) ls[strlen(ls)-1]='\0';
  2315.     // sauter espaces en dΘbut
  2316.     a=ls; while((*a==' ') || (*a=='\t')) a++;
  2317.     strcpy(s,a);
  2318.     //
  2319.     freet(ls);
  2320.   }
  2321. }
  2322. void linput_cpp(FILE* fp,char* s,int max) {
  2323.   s[0]='\0';
  2324.   do {
  2325.     if (s[strlen(s)-1]=='\\') s[strlen(s)-1]='\0';      // couper \ final
  2326.     // lire ligne
  2327.     linput_trim(fp,s+strlen(s),max-strlen(s));
  2328.   } while((s[strlen(s)-1]=='\\') && ((int)strlen(s)<max));
  2329. }
  2330.  
  2331. // idem avec les car spΘciaux
  2332. void rawlinput(FILE* fp,char* s,int max) {
  2333.   register int c;
  2334.   register int j=0;
  2335.   do {
  2336.     c=fgetc(fp);
  2337.     if (c!=EOF) {
  2338.       switch(c) {
  2339.         case 13: break;  // sauter CR
  2340.         case 10: c=-1; break;
  2341.         default: s[j++]=(char) c; break;
  2342.       }
  2343.     }
  2344.   }  while((c!=-1) && (c!=EOF) && (j<(max-1)));
  2345.   s[j++]='\0';
  2346. }
  2347.  
  2348.  
  2349. // compare le dΘbut de f avec s et retourne la position de la fin
  2350. // 'A=a' (case insensitive)
  2351. int strfield(const char* f,const char* s) {
  2352.   register int r=0;
  2353.   while (streql(*f,*s) && ((*f)!=0) && ((*s)!=0)) { f++; s++; r++; }
  2354.   if (*s==0)
  2355.     return r;
  2356.   else
  2357.     return 0;
  2358. }
  2359.  
  2360. //cherche chaine, case insensitive
  2361. char* strstrcase(char *s,char *o) {
  2362.   while((*s) && (strfield(s,o)==0)) s++;
  2363.   if (*s=='\0') return NULL;
  2364.   return s;  
  2365. }
  2366.  
  2367.  
  2368. // le fichier est-il un fichier html?
  2369. //  0 : non
  2370. //  1 : oui
  2371. // -1 : on sait pas
  2372. // -2 : on sait pas, pas d'extension
  2373. int ishtml(char* fil) {
  2374.   char *a;
  2375.  
  2376.   // patch pour les truc.html?Choix=toto
  2377.   if ( (a=strchr(fil,'?')) )  // paramΦtres?
  2378.     a--;  // pointer juste avant le ?
  2379.   else
  2380.     a=fil+strlen(fil)-1;  // pointer sur le dernier caractΦre
  2381.  
  2382.   if (*a=='/') return -1;    // rΘpertoire, on sait pas!!
  2383.   //if (*a=='/') return 1;    // ok rΘpertoire, html
  2384.  
  2385.   while ( (*a!='.') && (*a!='/')  && ((int) a>(int) fil)) a--;
  2386.   if (*a=='.') {  // a une extension
  2387.     char fil_noquery[HTS_URLMAXSIZE*2];
  2388.     fil_noquery[0]='\0';
  2389.     a++;  // pointer sur extension
  2390.     strncat(fil_noquery,a,HTS_URLMAXSIZE);
  2391.     a=strchr(fil_noquery,'?');
  2392.     if (a)
  2393.       *a='\0';
  2394.     return ishtml_ext(fil_noquery);     // retour
  2395.   } else return -2;   // indΘterminΘ, par exemple /truc
  2396. }
  2397.  
  2398. // idem, mais pour uniquement l'extension
  2399. int ishtml_ext(char* a) {
  2400.   int html=0;  
  2401.   //
  2402.   if (strfield2(a,"html"))       html = 1;
  2403.   else if (strfield2(a,"htm"))   html = 1;
  2404.   else if (strfield2(a,"shtml")) html = 1;
  2405.   else if (strfield2(a,"phtml")) html = 1;
  2406.   else if (strfield2(a,"htmlx")) html = 1;
  2407.   else if (strfield2(a,"shtm"))  html = 1;
  2408.   else if (strfield2(a,"phtm"))  html = 1;
  2409.   else if (strfield2(a,"htmx"))  html = 1;
  2410.   //
  2411.   // insuccΦs..
  2412.   else {
  2413.     switch(is_knowntype(a)) {
  2414.     case 1:
  2415.       html = 0;     // connu, non html
  2416.       break;
  2417.     case 2:
  2418.       html = 1;     // connu, html
  2419.       break;
  2420.     default:
  2421.       html = -1;    // inconnu..
  2422.       break;
  2423.     }
  2424.   }
  2425.   return html;  
  2426. }
  2427.  
  2428. // error (404,500..)
  2429. HTS_INLINE int ishttperror(int err) {
  2430.   switch (err/100) {
  2431.     case 4: case 5: return 1;
  2432.       break;
  2433.   }
  2434.   return 0;
  2435. }
  2436.  
  2437.  
  2438. // retourne le pointeur ou le pointeur + offset si il existe dans la chaine un @ signifiant une identification
  2439. char* jump_identification(char* source) {
  2440.   char *a,*b;
  2441.   // rechercher dernier @ (car parfois email transmise dans adresse!)
  2442.   // mais sauter ftp:// Θventuel
  2443.   a = jump_protocol(source);
  2444.   while( (b = strchr(a,'@')) ) {
  2445.     char* c;
  2446.     if ( (c=strchr(a,'/')) )        /* si un / est trouvΘ */
  2447.     if ((int) c < (int) b)      /* avant le @ */
  2448.       return a;                 /* alors exit (http://www.foo.bar/1.html@A20) */
  2449.     a=b+1;
  2450.   }
  2451.   return a;
  2452. }
  2453.  
  2454. // retourner adr sans ftp://
  2455. HTS_INLINE char* jump_protocol(char* source) {
  2456.   int p;
  2457.   // scheme
  2458.   // "Comparisons of scheme names MUST be case-insensitive" (RFC2616)
  2459.   if ((p=strfield(source,"http:")))
  2460.     source+=p;
  2461.   else if ((p=strfield(source,"ftp:")))
  2462.     source+=p;
  2463.   // net_path
  2464.   if ((p=strfield(source,"//")))
  2465.     source+=p;
  2466.   return source;
  2467. }
  2468.  
  2469. // codage base 64 a vers b
  2470. void code64(char* a,char* b) {
  2471.   int i1=0,i2=0,i3=0,i4=0;
  2472.   unsigned long store;
  2473.   int n;
  2474.   const char _hts_base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  2475.   b[0]='\0';
  2476.   while(*a) {  
  2477.     // 24 bits
  2478.     n=1; store=0; store |= ((*a++) & 0xff);
  2479.     if (*a) { n=2; store <<= 8; store |= ((*a++) & 0xff); }
  2480.     if (*a) { n=3; store <<= 8; store |= ((*a++) & 0xff); }
  2481.     if (n==3) {
  2482.       i4=store & 63;
  2483.       i3=(store>>6) & 63;
  2484.       i2=(store>>12) & 63;
  2485.       i1=(store>>18) & 63;
  2486.     } else if (n==2) {
  2487.       store<<=2;    
  2488.       i3=store & 63;
  2489.       i2=(store>>6) & 63;
  2490.       i1=(store>>12) & 63;
  2491.     } else {
  2492.       store<<=4;
  2493.       i2=store & 63;
  2494.       i1=(store>>6) & 63;
  2495.     }
  2496.     
  2497.     *b++ = _hts_base64[i1];
  2498.     *b++ = _hts_base64[i2];
  2499.     if (n>=2)
  2500.       *b++ = _hts_base64[i3];
  2501.     else
  2502.       *b++ = '=';
  2503.     if (n>=3)
  2504.       *b++ = _hts_base64[i4];
  2505.     else
  2506.       *b++ = '=';
  2507.   }
  2508.   *b++='\0';
  2509. }
  2510.  
  2511. // remplacer " par " etc..
  2512. // buffer MAX 1Ko
  2513. void unescape_amp(char* s) {
  2514.   while(*s) {
  2515.     if (*s=='&') {
  2516.       char* end=strchr(s,';');
  2517.       if ( ((int) end - (int) s) <= 8) {
  2518.         char c=0;
  2519.         if (strfield(s,"&"))
  2520.           c='&';
  2521.         else if (strfield(s,"°"))
  2522.           c='░';
  2523.         else if (strfield(s,">"))
  2524.           c='>';
  2525.         else if (strfield(s,"«"))
  2526.           c='\"';
  2527.         else if (strfield(s,"<"))
  2528.           c='<';
  2529.         else if (strfield(s," "))
  2530.           c=' ';
  2531.         else if (strfield(s,"""))
  2532.           c='\"';
  2533.         else if (strfield(s,"»"))
  2534.           c='\"';
  2535.         else if (strfield(s,"­"))
  2536.           c='-';
  2537.         else if (strfield(s,"˜"))
  2538.           c='~';
  2539.         else if (strfield(s,"&"))
  2540.           c='&';
  2541.         // remplacer?
  2542.         if (c) {
  2543.           char buff[HTS_URLMAXSIZE*2];
  2544.           buff[0]=c;
  2545.           strcpy(buff+1,end+1);
  2546.           strcpy(s,buff);
  2547.         }
  2548.       }
  2549.     }
  2550.     s++;
  2551.   }
  2552. }
  2553.  
  2554. // remplacer %20 par ' ', | par : etc..
  2555. // buffer MAX 1Ko
  2556. char* unescape_http(char* s) {
  2557.   static char tempo[HTS_URLMAXSIZE*2];
  2558.   int i,j=0;
  2559.   for (i=0;i<(int) strlen(s);i++) {
  2560.     if (s[i]=='%') {
  2561.       i++;
  2562.       tempo[j++]=(char) ehex(s+i);
  2563.       i++;    // sauter 2 caractΦres finalement
  2564.     }
  2565.     /*
  2566.     NON a cause de trucs comme /home/0,1837,1|7|1173|Content,00.html
  2567.     else if (s[i]=='|') {                     // exemple: file:///C|Program%20Files...
  2568.       tempo[j++]=':';
  2569.     }
  2570.     */
  2571.     else
  2572.       tempo[j++]=s[i];
  2573.   }
  2574.   tempo[j++]='\0';
  2575.   return tempo;
  2576. }
  2577.  
  2578. // unescape in URL/URI ONLY what has to be escaped, to form a standard URL/URI
  2579. char* unescape_http_unharm(char* s) {
  2580.   static char tempo[HTS_URLMAXSIZE*2];
  2581.   int i,j=0;
  2582.   for (i=0;i<(int) strlen(s);i++) {
  2583.     if (s[i]=='%') {
  2584.       int nchar=(char) ehex(s+i+1);
  2585.  
  2586.       int test = (  CHAR_RESERVED(nchar)
  2587.                 || CHAR_DELIM(nchar)
  2588.                 || CHAR_UNWISE(nchar)
  2589.                 || CHAR_SPECIAL(nchar)
  2590.                 || CHAR_XXAVOID(nchar) );
  2591.  
  2592.       if (!test) {
  2593.         tempo[j++]=(char) ehex(s+i+1);
  2594.         i+=2;
  2595.       } else {
  2596.         tempo[j++]='%';
  2597.       }
  2598.     }
  2599.     /*
  2600.     NON a cause de trucs comme /home/0,1837,1|7|1173|Content,00.html
  2601.     else if (s[i]=='|') {                     // exemple: file:///C|Program%20Files...
  2602.       tempo[j++]=':';
  2603.     }
  2604.     */
  2605.     else
  2606.       tempo[j++]=s[i];
  2607.   }
  2608.   tempo[j++]='\0';
  2609.   return tempo;
  2610. }
  2611.  
  2612. // remplacer " par %xx etc..
  2613. // buffer MAX 1Ko
  2614. void escape_spc_url(char* s) {
  2615.   x_escape_http(s,2);
  2616. }
  2617. // smith / john -> smith%20%2f%20john
  2618. void escape_in_url(char* s) {
  2619.   x_escape_http(s,1);
  2620. }
  2621. // smith / john -> smith%20/%20john
  2622. void escape_uri(char* s) {
  2623.   x_escape_http(s,3);
  2624. }
  2625. void escape_check_url(char* s) {
  2626.   x_escape_http(s,0);
  2627. }
  2628. void x_escape_http(char* s,int mode) {
  2629.   while(*s) {
  2630.     int test=0;
  2631.     if (mode == 0)
  2632.       test=(strchr("\" ",*s)!=0);
  2633.     else if (mode==1) {
  2634.       test = (  CHAR_RESERVED(*s)
  2635.              || CHAR_DELIM(*s)
  2636.              || CHAR_UNWISE(*s)
  2637.              || CHAR_SPECIAL(*s)
  2638.              || CHAR_XXAVOID(*s) );
  2639.     }
  2640.     else if (mode==2)
  2641.       test=(strchr(" ",*s)!=0);           // n'escaper que espace
  2642.     else if (mode==3) {                   // Θchapper que ce qui est nΘcessaire
  2643.       test = (
  2644.                 CHAR_SPECIAL(*s)
  2645.              || CHAR_XXAVOID(*s) );
  2646.     }
  2647.  
  2648.     if (test) {
  2649.       char buffer[HTS_URLMAXSIZE*2];
  2650.       int n;
  2651.       n=(int)(unsigned char) *s;
  2652.       strcpy(buffer,s+1);
  2653.       sprintf(s,"%%%02x",n);
  2654.       strcat(s,buffer);
  2655.     }
  2656.     s++;
  2657.   }
  2658. }
  2659.  
  2660.  
  2661. HTS_INLINE int ehexh(char c) {
  2662.   if ((c>='0') && (c<='9')) return c-'0';
  2663.   if ((c>='a') && (c<='f')) c-=('a'-'A');
  2664.   if ((c>='A') && (c<='F')) return (c-'A'+10);
  2665.   return 0;
  2666. }
  2667.  
  2668. HTS_INLINE int ehex(char* s) {
  2669.   return 16*ehexh(*s)+ehexh(*(s+1));
  2670.  
  2671. }
  2672.  
  2673. // concat, concatΦne deux chaines et renvoi le rΘsultat
  2674. // permet d'allΘger grandement le code
  2675. // il faut savoir qu'on ne peut mettre plus de 8 concat() dans une expression
  2676. char* concat(const char* a,const char* b) {
  2677.   static char buff[16][HTS_URLMAXSIZE*2];
  2678.   static int rol;
  2679.   rol=((rol+1)%16);    // roving pointer
  2680.   strcpy(buff[rol],a);
  2681.   if (b) strcat(buff[rol],b);
  2682.   return buff[rol];
  2683. }
  2684. // conversion fichier / -> antislash
  2685. #if HTS_DOSNAME
  2686. char* __fconv(char* a) {
  2687.   int i;
  2688.   for(i=0;i<(int) strlen(a);i++)
  2689.     if (a[i]=='/')  // convertir
  2690.       a[i]='\\';
  2691.   return a;
  2692. }
  2693. char* fconcat(char* a,char* b) {
  2694.   return __fconv(concat(a,b));
  2695. }
  2696. char* fconv(char* a) {
  2697.   return __fconv(concat(a,""));
  2698. }
  2699. #endif
  2700.  
  2701. /* / et \\ en / */
  2702. char* __fslash(char* a) {
  2703.   int i;
  2704.   for(i=0;i<(int) strlen(a);i++)
  2705.     if (a[i]=='\\')  // convertir
  2706.       a[i]='/';
  2707.   return a;
  2708. }
  2709. char* fslash(char* a) {
  2710.   return __fslash(concat(a,""));
  2711. }
  2712.  
  2713. // conversion minuscules, avec buffer
  2714. char* convtolower(char* a) {
  2715.   static char buff[16][HTS_URLMAXSIZE*2];
  2716.   static int rol;
  2717.   rol=((rol+1)%16);    // roving pointer
  2718.   strcpy(buff[rol],a);
  2719.   hts_lowcase(buff[rol]);  // lower case
  2720.   return buff[rol];
  2721. }
  2722.  
  2723. // conversion en minuscules
  2724. void hts_lowcase(char* s) {
  2725.   register int i;
  2726.   for(i=0;i<(int) strlen(s);i++)
  2727.     if ((s[i]>='A') && (s[i]<='Z'))
  2728.       s[i]+=('a'-'A');
  2729. }
  2730.  
  2731. // remplacer un caractΦre d'une chaεne dans une autre
  2732. HTS_INLINE void hts_replace(char *s,char from,char to) { 
  2733.   register char* a;
  2734.   while ((a=strchr(s,from))!=NULL) {
  2735.     *a=to;
  2736.   }
  2737. }
  2738.  
  2739.  
  2740. // caractΦre espace, guillemets, CR, LF etc..
  2741. /* SECTION OPTIMISEE:
  2742.   #define  is_space(c) (strchr(" \"\x0d\x0a\x09'",c)!=NULL)
  2743.   #define  is_realspace(c) (strchr(" \x0d\x0a\x09",c)!=NULL)
  2744. */
  2745. /*
  2746. HTS_INLINE int is_space(char c) {
  2747.   if (c==' ')  return 1;  // spc
  2748.   if (c=='"')  return 1;  // quote
  2749.   if (c==10)   return 1;  // lf
  2750.   if (c==13)   return 1;  // cr
  2751.   if (c=='\'') return 1;  // quote
  2752.   //if (c=='`')  return 1;  // backquote      << non
  2753.   if (c==9)    return 1;  // tab
  2754.   return 0;
  2755. }
  2756. */
  2757.  
  2758. // caractΦre espace, CR, LF, TAB
  2759. /*
  2760. HTS_INLINE int is_realspace(char c) {
  2761.   if (c==' ')  return 1;  // spc
  2762.   if (c==10)   return 1;  // lf
  2763.   if (c==13)   return 1;  // cr
  2764.   if (c==9)    return 1;  // tab
  2765.   return 0;
  2766. }
  2767. */
  2768.  
  2769.  
  2770.  
  2771.  
  2772.  
  2773. // deviner type d'un fichier local..
  2774. // ex: fil="toto.gif" -> s="image/gif"
  2775. void guess_httptype(char *s,char *fil) {
  2776.   get_httptype(s,fil,1);
  2777. }
  2778. // idem
  2779. // flag: 1 si toujours renvoyer un type
  2780. void get_httptype(char *s,char *fil,int flag) {
  2781.   if (ishtml(fil)==1)
  2782.     strcpy(s,"text/html");
  2783.   else {
  2784.     char *a=fil+strlen(fil)-1;    
  2785.     while ( (*a!='.') && (*a!='/')  && (a>fil)) a--;
  2786.     if (*a=='.') {
  2787.       int ok=0;
  2788.       int j=0;
  2789.       a++;
  2790.       while( (!ok) && (strnotempty(hts_mime[j][1])) ) {
  2791.         if (strfield2(hts_mime[j][1],a)) {
  2792.           if (hts_mime[j][0][0]!='*') {    // Une correspondance existe
  2793.             strcpy(s,hts_mime[j][0]);
  2794.             ok=1;
  2795.           }
  2796.         }
  2797.         j++;
  2798.       }
  2799.       
  2800.       if (!ok) if (flag) sprintf(s,"application/%s",a);
  2801.     } else {
  2802.       if (flag) strcpy(s,"application/octet-stream");
  2803.     }
  2804.   }
  2805. }
  2806.  
  2807. // get type of fil (php)
  2808. // s: buffer (text/html) or NULL
  2809. // return: 1 if known by user
  2810. int get_userhttptype(int setdefs,char *s,char *ext) {
  2811.   static char* buffer=NULL;
  2812.   if (setdefs) {
  2813.     buffer=s;
  2814.     return 1;
  2815.   } else {
  2816.     if (s)
  2817.       s[0]='\0';
  2818.     if (!ext)
  2819.       return 0;
  2820.     if (buffer) {
  2821.       char search[1024];
  2822.       char* detect;
  2823.       sprintf(search,"\n%s=",ext);    // php=text/html
  2824.       detect=strstr(buffer,search);
  2825.       if (!detect) {
  2826.         sprintf(search,"\n%s\n",ext); // php\ncgi=text/html
  2827.         detect=strstr(buffer,search);
  2828.       }
  2829.       if (detect) {
  2830.         detect=strchr(detect,'=');
  2831.         if (detect) {
  2832.           detect++;
  2833.           if (s) {
  2834.             char* a;
  2835.             a=strchr(detect,'\n');
  2836.             if (a) {
  2837.               strncat(s,detect,(int) a - (int) detect);
  2838.             }
  2839.           }
  2840.           return 1;
  2841.         }
  2842.       }
  2843.     }
  2844.   }
  2845.   return 0;
  2846. }
  2847. // renvoyer extesion d'un type mime..
  2848. // ex: "image/gif" -> gif
  2849. void give_mimext(char *s,char *st) {   
  2850.   int ok=0;
  2851.   int j=0;
  2852.   s[0]='\0';
  2853.   while( (!ok) && (strnotempty(hts_mime[j][1])) ) {
  2854.     if (strfield2(hts_mime[j][0],st)) {
  2855.       if (hts_mime[j][1][0]!='*') {    // Une correspondance existe
  2856.         strcpy(s,hts_mime[j][1]);
  2857.         ok=1;
  2858.       }
  2859.     }
  2860.     j++;
  2861.   }
  2862.   // wrap "x" mimetypes, such as:
  2863.   // application/x-mp3
  2864.   // or
  2865.   // application/mp3
  2866.   if (!ok) {
  2867.     int p;
  2868.     char* a=NULL;
  2869.     if ((p=strfield(st,"application/x-")))
  2870.       a=st+p;
  2871.     else if ((p=strfield(st,"application/")))
  2872.       a=st+p;
  2873.     if (a) {
  2874.       if ((int)strlen(a) >= 1) {
  2875.         if ((int)strlen(a) <= 4) {
  2876.           strcpy(s,a);
  2877.           ok=1;
  2878.         }
  2879.       }
  2880.     }
  2881.   }
  2882. }
  2883. // extension connue?..
  2884. //  0 : non
  2885. //  1 : oui
  2886. //  2 : html
  2887. int is_knowntype(char *fil) {
  2888.   int j=0;
  2889.   if (!fil)
  2890.     return 0;
  2891.   while(strnotempty(hts_mime[j][1])) {
  2892.     if (strfield2(hts_mime[j][1],fil)) {
  2893.       if (strfield2(hts_mime[j][0],"text/html"))
  2894.         return 2;
  2895.       else
  2896.         return 1;
  2897.     }
  2898.     j++;
  2899.   }
  2900.  
  2901.   // Known by user?
  2902.   return (is_userknowntype(fil));
  2903. }
  2904. // extension : html,gif..
  2905. char* get_ext(char *fil) {
  2906.   static char fil_noquery[HTS_URLMAXSIZE*2];
  2907.   char *a=fil+strlen(fil)-1;    
  2908.   while ( (*a!='.') && (*a!='/')  && (a>fil)) a--;
  2909.   if (*a=='.') {
  2910.     fil_noquery[0]='\0';
  2911.     a++;  // pointer sur extension
  2912.     strncat(fil_noquery,a,HTS_URLMAXSIZE);
  2913.     a=strchr(fil_noquery,'?');
  2914.     if (a)
  2915.       *a='\0';
  2916.     return concat(fil_noquery,"");
  2917.   }
  2918.   else
  2919.     return "";
  2920. }
  2921. // known type?..
  2922. //  0 : no
  2923. //  1 : yes
  2924. //  2 : html
  2925. // setdefs : set mime buffer:
  2926. //   file=(char*) "asp=text/html\nphp=text/html\n"
  2927. int is_userknowntype(char *fil) {
  2928.   char mime[1024];
  2929.   if (!fil)
  2930.     return 0;
  2931.   if (!strnotempty(fil))
  2932.     return 0;
  2933.   mime[0]='\0';
  2934.   get_userhttptype(0,mime,fil);
  2935.   if (!strnotempty(mime))
  2936.     return 0;
  2937.   else if (strfield2(mime,"text/html"))
  2938.     return 2;
  2939.   else
  2940.     return 1;
  2941. }
  2942.  
  2943. // page dynamique?
  2944. // is_dyntype(get_ext("foo.asp"))
  2945. int is_dyntype(char *fil) {
  2946.   int j=0;
  2947.   if (!fil)
  2948.     return 0;
  2949.   if (!strnotempty(fil))
  2950.     return 0;
  2951.   while(strnotempty(hts_ext_dynamic[j])) {
  2952.     if (strfield2(hts_ext_dynamic[j],fil)) {
  2953.       return 1;
  2954.     }
  2955.     j++;
  2956.   }
  2957.   return 0;
  2958. }
  2959.  
  2960. // types critiques qui ne doivent pas Ωtre changΘs car renvoyΘs par des serveurs qui ne
  2961. // connaissent pas le type
  2962. int may_unknown(char* st) {
  2963.   int j=0;
  2964.   // types mΘdia
  2965.   if (may_be_hypertext_mime(st))
  2966.     return 1;
  2967.   while(strnotempty(hts_mime_keep[j])) {
  2968.     if (strfield2(hts_mime_keep[j],st)) {      // trouvΘ
  2969.       return 1;
  2970.     }
  2971.     j++;
  2972.   }    
  2973.   return 0;
  2974. }
  2975.  
  2976.  
  2977.  
  2978. // -- Utils fichiers
  2979.  
  2980. // pretty print for i/o
  2981. void fprintfio(FILE* fp,char* buff,char* prefix) {
  2982.   char nl=1;
  2983.   while(*buff) {
  2984.     switch(*buff) {
  2985.     case 13: break;
  2986.     case 10:
  2987.       fprintf(fp,"\r\n");
  2988.       nl=1;
  2989.     break;
  2990.     default:
  2991.       if (nl)
  2992.         fprintf(fp,prefix);
  2993.       nl=0;
  2994.       fputc(*buff,fp);
  2995.     }
  2996.     buff++;
  2997.   }
  2998. }
  2999.  
  3000. /* Le fichier existe-t-il? (ou est-il HTS_ACCESSible?) */
  3001. int fexist(char* s) {
  3002.   FILE* fp;
  3003.   if (strnotempty(s)==0)     // nom vide: non trouvΘ
  3004.     return 0;
  3005.   fp=fopen(fconv(s),"rb");
  3006.   if (fp!=NULL) fclose(fp);
  3007.   return (fp!=NULL);
  3008.  
  3009. /* Taille d'un fichier, -1 si n'existe pas */
  3010. /* fp->_cnt ne fonctionne pas sur toute les plate-formes :-(( */
  3011. /* Note: NOT YET READY FOR 64-bit */
  3012. //LLint fsize(char* s) {
  3013. int fsize(char* s) {
  3014.   /*
  3015. #if HTS_WIN
  3016.   HANDLE hFile;
  3017.   DWORD dwSizeHigh = 0;
  3018.   DWORD dwSizeLow  = 0;
  3019.   hFile = CreateFile(s,0,0,NULL,OPEN_EXISTING,0,NULL);
  3020.   if (hFile) {
  3021.     dwSizeLow = GetFileSize (hFile, & dwSizeHigh) ;
  3022.     CloseHandle(hFile);
  3023.     if (dwSizeLow != 0xFFFFFFFF)
  3024.       return (dwSizeLow & (dwSizeHigh<<32));
  3025.     else
  3026.       return -1;
  3027.   } else
  3028.     return -1;
  3029. #else
  3030.     */
  3031.   FILE* fp;
  3032.   if (strnotempty(s)==0)     // nom vide: erreur
  3033.     return -1;
  3034.   fp=fopen(fconv(s),"rb");
  3035.   if (fp!=NULL) {
  3036.     int i;
  3037.     fseek(fp,0,SEEK_END);
  3038.     i=ftell(fp);
  3039.     fclose(fp);
  3040.     return i;
  3041.   } else return -1;
  3042.   /*
  3043. #endif
  3044.   */
  3045. }
  3046.  
  3047. int fpsize(FILE* fp) {
  3048.   int oldpos,size;
  3049.   if (!fp)
  3050.     return -1;
  3051.   oldpos=ftell(fp);
  3052.   fseek(fp,0,SEEK_END);
  3053.   size=ftell(fp);
  3054.   fseek(fp,oldpos,SEEK_SET);
  3055.   return size;
  3056. }
  3057.  
  3058. /* root dir, with ending / */
  3059. char* hts_rootdir(char* file) {
  3060.   static char path[1024+4];
  3061.   static int init=0;
  3062.   if (file) {
  3063.     if (!init) {
  3064.       path[0]='\0';
  3065.       init=1;
  3066.       if (strnotempty(file)) {
  3067.         char* a;
  3068.         strcpy(path,file);
  3069.         while((a=strrchr(path,'\\'))) *a='/';
  3070.         if ((a=strrchr(path,'/'))) {
  3071.           *(a+1)='\0';
  3072.         } else
  3073.           path[0]='\0';
  3074.       }
  3075.       if (!strnotempty(path)) {
  3076.         if( getcwd( path, 1024 ) == NULL )
  3077.             path[0]='\0';
  3078.         else
  3079.           strcat(path,"/");
  3080.       }
  3081.     }
  3082.     return NULL;
  3083.   } else if (init)
  3084.     return path;
  3085.   else
  3086.     return "";
  3087. }
  3088.  
  3089.  
  3090.  
  3091. hts_stat_struct HTS_STAT;
  3092. //
  3093. // return  number of downloadable bytes, depending on rate limiter
  3094. // see engine_stats() routine, too
  3095. // this routine works quite well for big files and regular ones, but apparently the rate limiter has
  3096. // some problems with very small files (rate too high)
  3097. LLint check_downloadable_bytes(int rate) {
  3098.   if (rate>0) {
  3099.     TStamp time_now;
  3100.     TStamp elapsed_useconds;
  3101.     LLint bytes_transfered_during_period;
  3102.     LLint left;
  3103.  
  3104.     // get the older timer
  3105.     int id_timer = (HTS_STAT.istat_idlasttimer + 1) % 2;
  3106.  
  3107.     time_now=mtime_local();
  3108.     elapsed_useconds = time_now - HTS_STAT.istat_timestart[id_timer];
  3109.     // NO totally stupid - elapsed_useconds+=1000;      // for the next second, too
  3110.     bytes_transfered_during_period = (HTS_STAT.HTS_TOTAL_RECV-HTS_STAT.istat_bytes[id_timer]);
  3111.     
  3112.     left = ((rate * elapsed_useconds)/1000) - bytes_transfered_during_period;
  3113.     if (left <= 0)
  3114.       left = 0;
  3115.     
  3116.     return left;
  3117.   } else
  3118.     return TAILLE_BUFFER;
  3119. }
  3120.  
  3121. //
  3122. // 0 : OK
  3123. // 1 : slow down
  3124. #if 0
  3125. int HTS_TOTAL_RECV_CHECK(int var) {
  3126.   if (HTS_STAT.HTS_TOTAL_RECV_STATE)
  3127.     return 1;
  3128.     /*
  3129.     {
  3130.     if (HTS_STAT.HTS_TOTAL_RECV_STATE==3) { 
  3131.       var = min(var,32); 
  3132.       Sleep(250); 
  3133.     } else if (HTS_STAT.HTS_TOTAL_RECV_STATE==2) { 
  3134.       var = min(var,256); 
  3135.       Sleep(100); 
  3136.     } else { 
  3137.       var/=2; 
  3138.       if (var<=0) var=1; 
  3139.       Sleep(50); 
  3140.     } 
  3141.   }
  3142.     */
  3143.   return 0;
  3144. }
  3145. #endif
  3146.  
  3147. // Lecture dans buff de size octets au maximum en utilisant la socket r (structure htsblk)
  3148. HTS_INLINE int hts_read(htsblk* r,char* buff,int size) {
  3149.   register int retour;
  3150.   //  return read(soc,buff,size);
  3151.   if (r->is_file) {
  3152. #if HTS_WIDE_DEBUG    
  3153.     DEBUG_W("read\n");
  3154. #endif
  3155.     if (r->fp)
  3156.       retour=fread(buff,1,size,r->fp);
  3157.     else
  3158.       retour=-1;
  3159.   } else {
  3160. #if HTS_WIDE_DEBUG    
  3161.     DEBUG_W("recv\n");
  3162.     if (r->soc==INVALID_SOCKET)
  3163.       printf("!!WIDE_DEBUG ERROR, soc==INVALID hts_read\n");
  3164. #endif
  3165.     //HTS_TOTAL_RECV_CHECK(size);         // Diminuer au besoin si trop de donnΘes reτues
  3166.     retour=recv(r->soc,buff,size,0);
  3167.     if (retour>0)    // compter flux entrant
  3168.       HTS_STAT.HTS_TOTAL_RECV+=retour;
  3169.   }
  3170. #if HTS_WIDE_DEBUG    
  3171.   DEBUG_W("recv/read done\n");
  3172. #endif
  3173.   return retour;
  3174. }
  3175.  
  3176.  
  3177. // -- Gestion cache DNS --
  3178. // 'RX98
  3179. #if HTS_DNSCACHE
  3180.  
  3181. // 'capsule' contenant uniquement le cache
  3182. t_dnscache* _hts_cache(void) {
  3183.   static t_dnscache cache;
  3184.   return &cache;
  3185. }
  3186.  
  3187. // lock le cache dns pour tout opΘration d'ajout
  3188. // plus prudent quand plusieurs threads peuvent Θcrire dedans..
  3189. // -1: status? 0: libΘrer 1:locker
  3190.  
  3191. /* 
  3192.   Simple lock function for cache
  3193.  
  3194.   Return value: always 0
  3195.   Parameter:
  3196.   1 wait for lock (mutex) available and lock it
  3197.   0 unlock the mutex
  3198.   [-1 check if locked (always return 0 with mutex)]
  3199.   -999 initialize
  3200. */
  3201. #if USE_BEGINTHREAD
  3202. int _hts_lockdns(int i) {
  3203.   static PTHREAD_LOCK_TYPE hMutex; 
  3204.   return htsSetLock(&hMutex,i);
  3205. }
  3206. #else
  3207. int _hts_lockdns(int i) {
  3208.   static int l=0;
  3209.   if (i>=0)
  3210.     l=i;
  3211.   return l;
  3212. }
  3213. #endif
  3214.  
  3215. // routine pour le cache - retour optionnel α donner α chaque fois
  3216. // NULL: nom non encore testΘ dans le cache
  3217. // si h_length==0 alors le nom n'existe pas dans le dns
  3218. t_hostent* _hts_ghbn(t_dnscache* cache,char* iadr,t_hostent* retour) {
  3219.   // attendre que le cache dns soit prΩt
  3220.   while(_hts_lockdns(-1));  // attendre libΘration
  3221.   _hts_lockdns(1);          // locker
  3222.  
  3223.   while(1) {
  3224.     if (strcmp(cache->iadr,iadr)==0) {  // ok trouvΘ
  3225.       if (cache->host_length>0) {  // entrΘe valide
  3226.         if (retour->h_addr)
  3227.           bcopy(cache->host_addr,(char *)retour->h_addr,cache->host_length);
  3228.         retour->h_length=cache->host_length;
  3229.       } else if (cache->host_length==0) {  // en cours
  3230.         _hts_lockdns(0);          // dΘlocker
  3231.         return NULL;
  3232.       } else {                    // erreur dans le dns, dΘja vΘrifiΘ
  3233.         if (retour->h_addr)
  3234.           retour->h_addr[0]='\0';
  3235.         retour->h_length=0;  // erreur, n'existe pas
  3236.       }
  3237.       _hts_lockdns(0);          // dΘlocker
  3238.       return retour;
  3239.     } else {    // on a pas encore trouvΘ
  3240.       if (cache->n!=NULL) { // chercher encore
  3241.         cache=cache->n;   // suivant!
  3242.       } else {
  3243.         _hts_lockdns(0);          // dΘlocker
  3244.         return NULL;    // non prΘsent        
  3245.       }
  3246.     }    
  3247.   }
  3248. }
  3249.  
  3250. // tester si iadr a dΘja ΘtΘ testΘ (ou en cours de test)
  3251. // 0 non encore
  3252. // 1 ok
  3253. // 2 non prΘsent
  3254. int hts_dnstest(char* _iadr) {
  3255.   static char iadr[HTS_URLMAXSIZE*2];
  3256.   t_dnscache* cache=_hts_cache();  // adresse du cache 
  3257.  
  3258.   // sauter user:pass@ Θventuel
  3259.   strcpy(iadr,jump_identification(_iadr));
  3260.   // couper Θventuel :
  3261.   {
  3262.     char *a;
  3263.     if ( (a=strchr(iadr,':')) )
  3264.       *a='\0';
  3265.   }
  3266.  
  3267. #if HTS_WIN
  3268.   if (inet_addr(iadr)!=INADDR_NONE)  // numΘrique
  3269. #else
  3270.   if (inet_addr(iadr)!=(in_addr_t) -1 )  // numΘrique
  3271. #endif
  3272.     return 1;
  3273.  
  3274.   while(_hts_lockdns(-1));  // attendre libΘration
  3275.   _hts_lockdns(1);          // locker
  3276.   while(1) {
  3277.     if (strcmp(cache->iadr,iadr)==0) {  // ok trouvΘ
  3278.       _hts_lockdns(0);          // dΘlocker
  3279.       return 1;    // prΘsent!
  3280.     } else {    // on a pas encore trouvΘ
  3281.       if (cache->n!=NULL) { // chercher encore
  3282.         cache=cache->n;   // suivant!
  3283.       } else {
  3284.         _hts_lockdns(0);          // dΘlocker
  3285.         return 2;    // non prΘsent        
  3286.       }
  3287.     }    
  3288.   }
  3289. }
  3290.  
  3291. // cache dns interne α HTS // ** FREE A FAIRE sur la chaine
  3292. t_hostent* hts_gethostbyname(char* _iadr) {
  3293.   static char iadr[HTS_URLMAXSIZE*2];
  3294.   static t_hostent host;
  3295.   static char adr[HTS_URLMAXSIZE*2]="";  // buffer adr pour host
  3296.   static char* he[2];
  3297.   static unsigned long inetaddr;
  3298.   //
  3299.   t_dnscache* cache=_hts_cache();  // adresse du cache
  3300.   t_hostent* hp;
  3301.  
  3302.   strcpy(iadr,jump_identification(_iadr));
  3303.   // couper Θventuel :
  3304.   {
  3305.     char *a;
  3306.     if ( (a=strchr(adr,':')) )
  3307.       *a='\0';
  3308.   }
  3309.  
  3310.   // effacer structure de retour, crΘer nouvelle
  3311.   bzero((char *)&host,sizeof(t_hostent));  
  3312.   host.h_addr_list=he;
  3313.   he[0]=adr;
  3314.   he[1]=NULL;  
  3315.   host.h_length=0;  
  3316.   cache->iadr[0]='*';
  3317.   cache->iadr[1]='\0';
  3318.   
  3319.   /* get IP from the dns cache */
  3320.   hp = _hts_ghbn(cache,iadr,&host);
  3321.   if (hp) {
  3322.     if (hp->h_length>0)
  3323.       return hp;
  3324.     else
  3325.       return NULL;    // entrΘe erronΘe (erreur DNS) dans le DNS
  3326.   } else {  // non prΘsent dans le cache dns, tester
  3327.     t_dnscache* c=cache;
  3328.     while(c->n) c=c->n;    // calculer queue
  3329.     
  3330. #if HTS_WIDE_DEBUG    
  3331.     DEBUG_W("gethostbyname\n");
  3332. #endif      
  3333. #if HDEBUG
  3334.     printf("gethostbyname (not in cache)\n");
  3335. #endif
  3336.     {
  3337. #if HTS_WIN
  3338.       if ((inetaddr=inet_addr(iadr))==INADDR_NONE) {
  3339. #else
  3340.       if ((inetaddr=inet_addr(iadr))==(in_addr_t) -1 ) {
  3341. #endif        
  3342. #if DEBUGDNS 
  3343.         printf("resolving (not cached) %s\n",iadr);
  3344. #endif
  3345.         hp=gethostbyname(iadr);  // calculer IP host
  3346.       } else {     // numΘrique, convertir sans passer par le dns
  3347.         host.h_addr=(char*) &inetaddr;
  3348.         host.h_length=4;
  3349.         hp=&host;
  3350.       }
  3351.     }
  3352. #if HTS_WIDE_DEBUG    
  3353.     DEBUG_W("gethostbyname done\n");
  3354. #endif
  3355.     cache->n=(t_dnscache*) calloct(1,sizeof(t_dnscache));
  3356.     if (cache->n!=NULL) {
  3357.       strcpy(cache->n->iadr,iadr);
  3358.       if (hp!=NULL) {
  3359.         bcopy(hp->h_addr,cache->n->host_addr,hp->h_length);
  3360.         cache->n->host_length=hp->h_length;
  3361.       } else {
  3362.         cache->n->host_addr[0]='\0';
  3363.         cache->n->host_length=0;  // non existant dans le dns
  3364.       }
  3365.       cache->n->n=NULL;
  3366.       return hp;
  3367.     } else {  // on peut pas noter, mais on peut renvoyer le rΘsultat
  3368.       return hp;
  3369.     }        
  3370.   }  // retour hp du cache
  3371. }
  3372.  
  3373. #else
  3374. HTS_INLINE t_hostent* hts_gethostbyname(char* iadr) {
  3375.   t_hostent* retour;
  3376. #if HTS_WIDE_DEBUG    
  3377.   DEBUG_W("gethostbyname (2)\n");
  3378. #endif
  3379. #if DEBUGDNS 
  3380.     printf("blocking method gethostbyname() in progress for %s\n",iadr);
  3381. #endif
  3382.   retour=gethostbyname(jump_identification(iadr));
  3383. #if HTS_WIDE_DEBUG    
  3384.   DEBUG_W("gethostbyname (2) done\n");
  3385. #endif
  3386.   return retour;
  3387. }
  3388. #endif
  3389.  
  3390.  
  3391. // --- Tracage des mallocs() ---
  3392. #if HTS_TRACE_MALLOC
  3393. typedef struct _mlink {
  3394.   void* adr;
  3395.   int len;
  3396.   int id;
  3397.   struct _mlink* next;
  3398. } mlink;
  3399. mlink trmalloc = {NULL,0,0,NULL};
  3400. int trmalloc_id=0;
  3401.  
  3402. HTS_INLINE void* hts_malloc(size_t len,size_t len2) {
  3403.   mlink* lnk = (mlink*) calloc(1,sizeof(mlink));
  3404.   void*  r   = NULL;
  3405.   if (lnk) {
  3406.     if (len2)
  3407.       r = calloc(len,len2);
  3408.     else
  3409.       r = malloc(len);
  3410.     if (r) {
  3411.       lnk->adr=r;
  3412.       if (len2)
  3413.         lnk->len=len*len2;
  3414.       else
  3415.         lnk->len=len;
  3416.       lnk->id=trmalloc_id++;
  3417.       lnk->next=trmalloc.next;
  3418.       trmalloc.next=lnk;
  3419. #if MEMDEBUG
  3420.       //printf("malloc: %d\n",r);
  3421. #endif
  3422.     } else free(lnk);
  3423.   }
  3424.   return r;
  3425. }
  3426. HTS_INLINE void  hts_free(void* adr) {
  3427.   mlink* lnk = &trmalloc;
  3428.   if (!adr) {
  3429. #if MEMDEBUG
  3430.     printf("* unexpected free() error at %d\n",adr);
  3431. #endif
  3432.     return;
  3433.   }
  3434.   do {
  3435.     if (lnk->next->adr==adr) {
  3436.       mlink* blk_free=lnk->next;
  3437. #if 1
  3438.       lnk->next=lnk->next->next;
  3439.       free((void*) blk_free);
  3440. #else
  3441. #if MEMDEBUG
  3442.       if (blk_free->id==-1) {
  3443.         printf("* memory has already been freed: %d (id=%d)\n",blk_free->adr,blk_free->id);
  3444.       }
  3445. #endif
  3446.       blk_free->id=-1;
  3447. #endif
  3448.       free(adr);
  3449. #if MEMDEBUG
  3450.       //printf("free: %d (id=%d)\n",blk_free->adr,blk_free->id);
  3451. #endif
  3452.       return;
  3453.     }
  3454.     lnk=lnk->next;
  3455.   } while(lnk->next != NULL);
  3456. #if MEMDEBUG
  3457.   printf("* unexpected free() error at %d\n",adr);
  3458. #endif
  3459.   free(adr);
  3460. }
  3461. HTS_INLINE void* hts_realloc(void* adr,size_t len) {
  3462.   mlink* lnk = &trmalloc;
  3463.   do {
  3464.     if (lnk->next->adr==adr) {
  3465.       adr = realloc(adr,len);
  3466.       lnk->next->adr = adr;
  3467.       lnk->next->len = len;
  3468. #if MEMDEBUG
  3469.       //printf("realloc: %d (id=%d)\n",lnk->next->adr,lnk->next->id);
  3470. #endif
  3471.       return adr;
  3472.     }
  3473.     lnk=lnk->next;
  3474.   } while(lnk->next != NULL);
  3475. #if MEMDEBUG
  3476.   printf("* unexpected realloc() error at %d\n",adr);
  3477. #endif
  3478.   return realloc(adr,len);
  3479. }
  3480. // check the malloct() and calloct() trace stack
  3481. void  hts_freeall(void) {
  3482.   while(trmalloc.next) {
  3483. #if MEMDEBUG
  3484.     printf("* block %d\t not released: at %d\t (%d\t bytes)\n",trmalloc.next->id,trmalloc.next->adr,trmalloc.next->len);
  3485. #endif
  3486.     if (trmalloc.next->id != -1) {
  3487.       freet(trmalloc.next->adr);
  3488.     }
  3489.   }
  3490. }
  3491. #endif
  3492.  
  3493.  
  3494. // -- divers //
  3495.  
  3496. // cut path and project name
  3497. // patch also initial path
  3498. void cut_path(char* fullpath,char* path,char* pname) {
  3499.   path[0]=pname[0]='\0';
  3500.   if (strnotempty(fullpath)) {
  3501.     if ((fullpath[strlen(fullpath)-1]=='/') || (fullpath[strlen(fullpath)-1]=='\\'))
  3502.       fullpath[strlen(fullpath)-1]='\0';
  3503.     if (strlen(fullpath)>1) {
  3504.       char* a;
  3505.       while( (a=strchr(fullpath,'\\')) ) *a='/';     // remplacer par /
  3506.       a=fullpath+strlen(fullpath)-2;
  3507.       while( (*a!='/') && ((int) a > (int) fullpath)) a--;
  3508.       if (*a=='/') a++;
  3509.       strcpy(pname,a);
  3510.       strncat(path,fullpath,(int) a-(int) fullpath);
  3511.     }
  3512.   }
  3513. }
  3514.  
  3515.  
  3516.  
  3517. // -- Gestion protocole ftp --
  3518.  
  3519. #if HTS_WIN
  3520. int ftp_available(void) {
  3521.   return 1;
  3522. }
  3523. #else
  3524. int ftp_available(void) {
  3525.   return 1;   // ok!
  3526.   //return 0;   // SOUS UNIX, PROBLEMES
  3527. }
  3528. #endif
  3529.  
  3530.  
  3531.  
  3532. int hts_init(void) {
  3533.   // default wrappers
  3534.   htswrap_init();
  3535.   htswrap_add("init",htsdefault_init);
  3536.   htswrap_add("free",htsdefault_uninit);
  3537.   htswrap_add("start",htsdefault_start);
  3538.   htswrap_add("change-options",htsdefault_chopt);
  3539.   htswrap_add("end",htsdefault_end);
  3540.   htswrap_add("check-html",htsdefault_checkhtml);
  3541.   htswrap_add("loop",htsdefault_loop);
  3542.   htswrap_add("query",htsdefault_query);
  3543.   htswrap_add("query2",htsdefault_query2);
  3544.   htswrap_add("query3",htsdefault_query3);
  3545.   htswrap_add("check-link",htsdefault_check);
  3546.   htswrap_add("pause",htsdefault_pause);
  3547.   htswrap_add("save-file",htsdefault_filesave);
  3548.   htswrap_add("link-detected",htsdefault_linkdetected);
  3549.   htswrap_add("transfer-status",htsdefault_xfrstatus);
  3550.   return 1;
  3551. }
  3552. // defaut wrappers
  3553. void __cdecl htsdefault_init(void) {
  3554. }
  3555. void __cdecl htsdefault_uninit(void) {
  3556. }
  3557. int __cdecl htsdefault_start(void* opt) {
  3558.   return 1; 
  3559. }
  3560. int __cdecl htsdefault_chopt(void* opt) {
  3561.   return 1;
  3562. }
  3563. int  __cdecl htsdefault_end(void) { 
  3564.   return 1; 
  3565. }
  3566. int __cdecl htsdefault_checkhtml(char* html,int len,char* url_adresse,char* url_fichier) {
  3567.   return 1;
  3568. }
  3569. int __cdecl htsdefault_loop(void* back,int back_max,int back_index,int lien_n,int lien_tot,int stat_time,hts_stat_struct* stats) {    // appelΘ α chaque boucle de HTTrack
  3570.   return 1;
  3571. }
  3572. char* __cdecl htsdefault_query(char* question) {
  3573.   return "";
  3574. }
  3575. char* __cdecl htsdefault_query2(char* question) {
  3576.   return "";
  3577. }
  3578. char* __cdecl htsdefault_query3(char* question) {
  3579.   return "";
  3580. }
  3581. int __cdecl htsdefault_check(char* adr,char* fil,int status) {
  3582.   return -1;
  3583. }
  3584. void __cdecl htsdefault_pause(char* lockfile) {
  3585.   while (fexist(lockfile)) {
  3586.     Sleep(1000);
  3587.   }
  3588. }
  3589. void __cdecl htsdefault_filesave(char* file) {
  3590. }
  3591. int __cdecl htsdefault_linkdetected(char* link) {
  3592.   return 1;
  3593. }
  3594. int __cdecl htsdefault_xfrstatus(void* back) {
  3595.   return 1;
  3596. }
  3597. // end defaut wrappers
  3598.  
  3599.  
  3600.  
  3601. // Fin
  3602.  
  3603.